javascript notes

javascript online code execution Must Watch!



MustWatch

SCRUD System Using Jquery Json And Datatables SCRUD: Search, Create, Read, Update and Delete

javascript Html Samples jquerySamples Access-Control-Allow-Origin javascriptSamples
demo2s-1 demo2s-2 demo2s-3 demo2s-4 demo2s-5 demo2s-6 demo2s-7 demo2s-8 demo2s-9 demo2s-10 demo2s-11 JavaScript Speech Recognition (Speech to Text) speech-to-text-app Speech Recognition from Speech to Text google Cloud Speech-to-Text convert speech into text webdevsimplified WebDevSimplified audio-book-reader Tesseractjs javascript library javascript exercises ADO Connection Object Build BIGGER Games Sprite Animation in JavaScript JavaScript Audio Visualizers JavaScript Character Animation JavaScript Audio CRASH COURSE 10 audio visualiser experiments Melody Maker app Audio Magic with JavaScript Network Diagrams with JavaScript Create JavaScript Network Graph Network graph D3 Network Diagram javascript samples javascriptBook js逆向 input table codepedia.info Hardware With JavaScript.html perlin noise Snake sineWaves Flow Fields Learn React In 30 Minutes Code Sine Waves Code rainbow Snakey An interactive visual circular motion using sine and cosine functions canvas Text nipplejs, A virtual joystick for touch capable interfaces FullPage.js: Help you to create full-screen scrolling websites
swiper.js & owl.carousel.js; Fully responsive, swipe-enabled, infinite looping, and more.
popper.js: to place the tooltip.
particles.js particles.js Javascript Game Engines JS Gaming Engines and Libraries for 2020 get client's IP address using JavaScript Javascript Libraries D3 Basic contour chart Learn jQuery JAVASCRIPT PROJECTS Make a Simple JavaScript Quiz JavascriptGame alligatorIoJs 88 functions plotly realtime chart anime.js howler.js chart.js reveal.js three.js Pixi.js video.js 10 Stunning CSS 3D Effect JavaScript in Half an Hour (Without jQuery!) W3JavascriptHowTo Get Started With Analyzing Runtime Performance jqueryui demos jqueryui tabs
JavaScript Tutorial Complete Guide to JavaScript Classes How To Code in JavaScript 15 JavaScript concepts Code Academy JavaScript tracks Eloquent JavaScript Advanced JavaScript
javascriptjanuary Basic Bar Chart pie basic chart webassembly
javascript mathjs Matrices Matrix math for the web Linear Algebra in JavaScript with Matrix Operations
pageX, pageY, screenX, screenY, clientX, and clientY

Javascript Animation

SVG Morphing Animation

,

GSAP Animation

,

Javascript Scroll Animation

,

Page Animations With Javascript

,

Fullpage Animations With Javascript

,

Javascript Animations

,

Liquid Image Transition With Javascript

,

Vanilla Javascript Text Animation

,

Create 3D Animation

3D Animation

React Tutorial

React Tutorial react CRUD operations

Node.js Tutorial

Node.js Tutorial for Beginners Node入門

process local files

Reading files in JavaScript using the File APIs 跨網域存取 Cross-Origin Resource Sharing (CORS) ==================== HTML5 fileReader facility Here's an example using FileReader: function readSingleFile(e) { var file = e.target.files[0]; if (!file) { return; } var reader = new FileReader(); reader.onload = function(e) { var contents = e.target.result; displayContents(contents); }; reader.readAsText(file); } function displayContents(contents) { var element = document.getElementById('file-content'); element.textContent = contents; } document.getElementById('file-input') .addEventListener('change', readSingleFile, false); <input type="file" id="file-input" /> <h3>Contents of the file:</h3> <pre id="file-content"></pre> The HTML5 fileReader facility does allow you to process local files, but these MUST be selected by the user, you cannot go rooting about the users disk looking for files. I currently use this with development versions of Chrome (6.x). I don't know what other browsers support it. ==================== Just use openFile(function to be executed with file contents as first parameter). function dispFile(contents) { document.getElementById('contents').innerHTML=contents } function clickElem(elem) {// Thx user1601638 on Stack Overflow (6/6/2018 - https://stackoverflow.com/questions/13405129/javascript-create-and-save-file )var eventMouse = document.createEvent("MouseEvents")eventMouse.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)elem.dispatchEvent(eventMouse) } function openFile(func) {readFile = function(e) { var file = e.target.files[0]; if (!file) { return; } var reader = new FileReader(); reader.onload = function(e) { var contents = e.target.result; fileInput.func(contents) document.body.removeChild(fileInput) } reader.readAsText(file)}fileInput = document.createElement("input")fileInput.type='file'fileInput.style.display='none'fileInput.onchange=readFilefileInput.func=funcdocument.body.appendChild(fileInput)clickElem(fileInput) } Click the button then choose a file to see its contents displayed below. <button onclick="openFile(dispFile)">Open a file</button> <pre id="contents"></pre> ======================= Try function readFile(file) { return new Promise((resolve, reject) => { let fr = new FileReader(); fr.onload = x=> resolve(fr.result); fr.readAsText(file); }) } but user need to take action to choose file ======================= Javascript cannot typically access local files in new browsers but the XMLHttpRequest object can be used to read files. So it is actually Ajax (and not Javascript) which is reading the file. If you want to read the file abc.txt, you can write the code as: var txt = ''; var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function(){ if(xmlhttp.status == 200 && xmlhttp.readyState == 4){ txt = xmlhttp.responseText; } }; xmlhttp.open("GET","abc.txt",true); xmlhttp.send(); Now txt contains the contents of the file abc.txt. ======================= javascript to read a local text file function getData(){ var xmlhttp; if (window.XMLHttpRequest) {xmlhttp = new XMLHttpRequest();} else {xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");} xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { var lines = xmlhttp.responseText; //*get all lines from file* intoArray(lines); *//call function with parameter "lines*" } } xmlhttp.open("GET", "motsim1.txt", true); xmlhttp.send(); } function intoArray (lines) { // split text data into array "\n" is splitting character var lineArr = lines.split('\n'); //just to check if it works output lineArr[index] as below document.write(lineArr[2]); document.write(lineArr[3]); }

======

Arrays

Arrays JavaScript Stack and Queue JavaScript Multidimensional array Javascript Array Processing
Merge Arrays
Fill Arrays
multiple dimensions array processing
map to array of arrays
get index of object in array
4 Methods to Search Through Arrays
Array.includes
Array.find
Array.findIndex
Array.indexOf
filter
forEach
Element-wise Operations

Element-wise Operations

a.map((e,i) => e + b[i]); a = [2,3,4] b = [4,7,90] returns [6,10,94]

Merge Arrays

combined2 = [...cars, ...trucks];

Fill Arrays

: arr = Array(5).fill(1); arr.fill(null,0,3); //array.fill(value, start, end)

multiple dimensions array processing

:

map to array of arrays

: arr = [[3.1042, 7.2351], [1.4564, 4.335], [5.523, 7.157]]; fixed = x => x.toFixed(2); arr = arr.map( subarray => subarray.map( fixed )); or arr = arr.map(function(subarray) { return subarray.map(function(number) { return fixed(number); }) })

get index of object in array

get index of object in array // Get index of object with specific value in array const needle = 3; // needle const haystack = [{ id: 1 }, { id: 2 }, { id: 3 }]; // haystack const index = haystack.findIndex(item => item.id === needle); // find the index of a value in an array var list = ["apple","banana","orange"] var index_of_apple = list.indexOf("apple") // 0 // findindex const array1 = [5, 12, 8, 130, 44]; const search = element => element > 13; console.log(array1.findIndex(search)); // expected output: 3 const array2 = [ { id: 1, dev: false }, { id: 2, dev: false }, { id: 3, dev: true } ]; const search = obj => obj.dev === true; console.log(array2.findIndex(search)); // 2 //find the index of an object in an array const letters = [{letter: 'a'},{letter: 'b'},{letter: 'c'}] const index = letters.findIndex((element, index) => { if (element.letter === 'b') { return true } }) //index is `1` // get index of element in array const beasts = ['ant', 'bison', 'camel', 'duck', 'bison']; beasts.indexOf('bison'); //ouput: 1 // start from index 2 beasts.indexOf('bison', 2); //output: 4 beasts.indexOf('giraffe'); //output: -1

4 Methods to Search Through Arrays

Array.includes

fruits = ["Banana", "Orange", "Apple", "Mango"]; fruits.includes("Mango"); // true fruits.includes("Man"); // false

Array.find

tree = ["birch", "maple", "oak", "poplar" ]; item = tree.find(name => name.startsWith("m")); // maple

Array.findIndex

fruits = ["Banana", "Orange", "Apple", "Mango"]; fruits.findIndex(element => element.includes("an")) // 0 fruits.findIndex(element => element.includes("ab")) // -1 fruits.find(element => element.includes("an")) // Banana fruits.filter(element => element.includes("an")); // Banana, Orange, Mango fruits.some(element => element.includes("ang")); // true

Array.indexOf

search and returns the position of the first occurrence of a specified value in a string. nameArr = ['sonarika','yogesh','sumit','vijay','anil']; nameArr.indexOf('sumit') // 2 nameArr.indexOf('vis') // -1 txt = "Sonarika Bhadoria"; txt.indexOf('a') // 3 arr = ["one", "two", "three", "four", "five"]; arr.includes("two"); // true arr.includes("tw"); // false

filter

search array for all substring match arr2 = fruits.filter(element => element.includes("ang")); ages = [12,14,19,21] function checkAdult(age) { return age >= 18; } ages.filter(checkAdult); ==== arr = [ 4, "Pete", 8, "John" ]; $.inArray( "Pete", arr ) // 1 $.inArray() returns index of the item in the array, or -1 if item was not found.

forEach

forEach is an Array method that we can use to execute a function on each element in an array. It can only be used on Arrays, Maps, and Sets. arr = ['cat', 'dog', 'fish']; arr.forEach(element => { console.log(element); }); // cat // dog // fish arr = [5,4,8,7]; arr.forEach(function(item,index,arr) { console.log("item: " + item + " at index: " + index + " in the array: " + arr); }) // item: 5 at index: 0 in the array: 5,4,8,7 // item: 4 at index: 1 in the array: 5,4,8,7 // item: 8 at index: 2 in the array: 5,4,8,7

JavaScript数组方法


forEach()
map()
filter()
reduce()
find() 和 findIndex()
some() 和 every()
includes()
flat()
提升你的开发效率

forEach()

forEach() 对数组中的每个元素执行一次回调函数。 它不创建新的数组。 const fruits = ["apple", "banana", "cherry"]; fruits.forEach(fruit => console.log(fruit));

map()

map() 根据你提供的回调函数,将每个元素转换成新的形式,并创建一个新的数组。 map() 成为数据转换的理想工具。 const numbers = [1, 2, 3, 4]; const doubledNumbers = numbers.map(number => number * 2); console.log(doubledNumbers); // Output [2, 4, 6, 8]

filter()

filter() 根据设定条件,筛选出符合条件的元素,并创建一个新的数组。 const numbers = [1, 2, 3, 4, 5]; const evenNumbers = numbers.filter(number => number % 2 === 0); console.log(evenNumbers); // Output [2, 4]

reduce()

reduce() 将数组中的所有元素通过定义的函数积累, 合成一个值。 const numbers = [1, 2, 3, 4]; const sum = numbers.reduce((accumulator, current) => accumulator + current, 0); console.log(sum); // Output: 10

find() 和 findIndex()

find() 和findIndex() 搜索满足条件的第一个元素或其索引。 const numbers = [1, 2, 4, 5]; const firstGreaterThanThree = numbers.find(number => number > 3); console.log(firstGreaterThanThree); // Output: 4 const numbers = [1, 2, 4, 5]; const indexOfFirstGreaterThanThree = numbers.findIndex(number => number > 3); console.log(indexOfFirstGreaterThanThree); // Output: 2

some() 和 every()

some() 和every() 检查数组中是否至少有一个或所有元素满足条件。 const numbers = [1, 5, 8, 12]; const hasElementGreaterThanTen = numbers.some(number => number > 10); console.log(hasElementGreaterThanTen); // Output: true const data = ["apple", "banana", 10]; const allStrings = data.every(element => typeof element === "string"); console.log(allStrings); // Output: false

includes()

includes() 告诉你数组中是否包含特定的值。 const fruits = ["apple", "banana", "cherry"]; const hasOrange = fruits.includes("orange"); console.log(hasOrange); // Output: false

flat()

flat() 将多维数组扁平化为一维数组。 const nestedArray = [1, [2, 3], 4]; const flattenedArray = nestedArray.flat(); console.log(flattenedArray); // Output: [1, 2, 3, 4]

find max in array of arrays

var array = [ [14, 23], [13, 47], [38, 35], [24, 34] ]; var maxRow = array.map(function(row){ return Math.max.apply(Math, row); }); Math.max(...maxRow) ymax: Math.max(...thedrawdata.map(function(row){ return Math.max.apply(Math, row);})),

Find difference between two arrays

remove another set var first = [ 1, 2, 3, 4, 5 ]; var second = [ 4, 5, 6 ]; var difference = first.filter(x => !second.includes(x)); var b = new Set(second); var difference = [...first].filter(x => !b.has(x));

create an array containing 1…N

In ES6 using Array from() and keys() methods. Array.from(Array(10).keys()) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Shorter version using spread operator. [...Array(10).keys()]

Array from() Method

Array.from(object, mapFunction, thisValue) The arr.from() method is used to creates a new array instance from a given array. In the case of a string, every alphabet of the string is converted to an element of the new array instance and in case of integer values, a new array instance simply takes the elements of the given array. var myArr = Array.from("ABCDEFG"); // Create an Array from a String: // A,B,C,D,E,F,G Array.from([1, 2, 3]) // 2,4,6

Array includes() Method

array.includes(element, start) Check if an array includes "Mango": var fruits = ["Banana", "Orange", "Apple", "Mango"]; var n = fruits.includes("Mango"); // true

Removing specific item from array

let value = 3 let arr = [1, 2, 3, 4, 5, 3] arr = arr.filter(item => item !== value) notvisitedList = notvisitedList.filter(item => item !== topicpointer); notvisitedList[Math.floor(Math.random() * notvisitedList.length)]; Removing multiple items An additional advantage of this method is that you can remove multiple items let forDeletion = [2, 3, 5] let arr = [1, 2, 3, 4, 5, 3] arr = arr.filter(item => !forDeletion.includes(item))

Arrays and loops

Understanding basic arrays and loops Understanding dense arrays Defining arrays & multi-dimensional arrays using literal notation Creating a custom two-dimensional array Converting objects to arrays using Array.prototype.slice.call() Sorting an array using the sort() method

arithmetic on two arrays

var a = [1,3,5,7,9]; var b = [5,4,3,2,1]; a.map((x, index)=> b[index] + x ); // [6, 7, 8, 9, 10]

Looping over arrays

while

let index = 0; const array = [1,2,3,4,5,6]; while (index < array.length) { console.log(array[index]); index++; }

for (classical)

const array = [1,2,3,4,5,6]; for (let index = 0; index < array.length; index++) { console.log(array[index]); }

forEach

const array = [1,2,3,4,5,6]; array.forEach(function(current_value, index, array) { console.log(`At index ${index} in array ${array} the value is ${current_value}`); }); // => undefined

map

The last construct was useful, however, it doesn’t return a new array which might be undesirable for your specific case. map solves this by applying a function over every element and then returning the new array. const array = [1,2,3,4,5,6]; const square = x => Math.pow(x, 2); const squares = array.map(square); console.log(`Original array: ${array}`); console.log(`Squared array: ${squares}`); The full signature for map is .map(current_value, index, array).

reduce

From MDN:
The reduce() method applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.
const array = [1,2,3,4,5,6]; const sum = (x, y) => x + y; const array_sum = array.reduce(sum, 0); console.log(`The sum of array: ${array} is ${array_sum}`);

filter

Filters elements on an array based on a boolean function. const array = [1,2,3,4,5,6]; const even = x => x % 2 === 0; const even_array = array.filter(even); console.log(`Even numbers in array ${array}: ${even_array}`);

every

Got an array and want to test if a given condition is met in every element? const array = [1,2,3,4,5,6]; const under_seven = x => x < 7; if (array.every(under_seven)) { console.log('Every element in the array is less than 7'); } else { console.log('At least one element in the array was bigger than 7'); }

some

Test if at least one element matches our boolean function. const array = [1,2,3,9,5,6,4]; const over_seven = x => x > 7; if (array.some(over_seven)) { console.log('At least one element bigger than 7 was found'); } else { console.log('No element bigger than 7 was found'); }

Find the Max of all the nested arrays

const arr = [[12,45,75], [54,45,2],[23,54,75,2]]; const max = Math.max(...[].concat(...arr));

如何合并两个对象

 1.1. 使用 Object.assign()
 1.2. 使用扩展运算符 (...)
 1.3. 使用 Object.assign() 和扩展运算符组合
 1.4. 注意事项
在 JavaScript 中,可以使用多种方式来合并两个对象。 1.1. 使用 Object.assign() 1.2. 使用扩展运算符 (...) 1.3. 使用 Object.assign() 和扩展运算符组合

 1.1. 使用 Object.assign()

Object.assign() 方法可以用来合并一个或多个对象到目标对象中。 它的第一个参数是目标对象,后面的参数都是源对象。 const obj1 = { a: 1, b: 2 }; const obj2 = { b: 3, c: 4 }; const mergedObj = Object.assign({}, obj1, obj2); console.log(mergedObj); // 输出: { a: 1, b: 3, c: 4 } 注意,如果目标对象和源对象有相同的键,那么源对象的键值会覆盖目标对象的键值。

 1.2. 使用扩展运算符 (...)

ES6 引入了扩展运算符,它可以用来复制可枚举的属性到新的对象中。 const obj1 = { a: 1, b: 2 }; const obj2 = { b: 3, c: 4 }; const mergedObj = { ...obj1, ...obj2 }; console.log(mergedObj); // 输出: { a: 1, b: 3, c: 4 } 这种方式同样会覆盖相同的键。

 1.3. 使用 Object.assign() 和扩展运算符组合

如果你想要合并的对象中有方法或者需要保持原有对象不变,你可以使用 Object.assign() 和扩展运算符的组合: const obj1 = { a: 1, b: 2, method: function() { console.log('method from obj1'); } }; const obj2 = { b: 3, c: 4, method: function() { console.log('method from obj2'); } }; // 使用 Object.assign 来合并方法 const mergedObj = Object.assign({}, obj1, obj2, { ...obj1, ...obj2 }); console.log(mergedObj); // 输出: { a: 1, b: 3, c: 4, method: [Function(anonymous)] } // 或者使用扩展运算符 const mergedObj2 = { ...obj1, ...obj2, ...obj1 }; console.log(mergedObj2); // 输出: { a: 1, b: 3, c: 4, method: [Function(anonymous)] }

 1.4. 注意事项

如果对象中有相同的键,那么后一个对象的值会覆盖前一个对象的值。 使用 Object.assign() 和扩展运算符时,默认只会浅拷贝第一层属性。 如果对象包含嵌套的对象,你需要进行深拷贝。 如果你希望进行深拷贝,可以考虑使用第三方库如 lodash 的 _.merge() 方法。

Four ways to merge arrays

1. Using for loop

We can loop through the array source array which need to be pushed , then add elements one by one function push(fromArray, toArray) { for(let i = 0, len = fromArray.length; i < len; i++) { toArray.push(fromArray[i]); } return toArray; } var array1 = [1,2,3,4,5];var array2= [6,7,8,9,10];var array3 = [];push(array1, array3);push(array2, array3);

2. Using spread operator

Spread syntax allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected var array1 = [1,2,3,4,5];var array2 = [6,7,8,9,10];var array3 = [...array1, ...array2];array3; // [1,2,3,4,5,6,7,8,9,10]; We can use spread operator with push var array1 = [1,2,3,4,5];var array2 = [6,7,8,9,10];var array3 = []array3.push(...array1, ...array2);array3; // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] We can also use spread operator with Array.of var array1 = [1,2,3,4,5] var array2 = [6,7,8,9,10];var array3 = Array.of(...array2, ...array1); We can use spread operator to convert string to array var string ="two";var arrayOfChar = [...string];arrayOfChar; //["t", "w", "o"]

3. Using concat method

The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array. var array1 = [1,2,3,4,5]var array2 = [6,7,8,9,10]; var array3 = array1.concat(array2);// orvar array3 = [].concat(array1, array2); We can pass other than array as arguments. var a = "string";var b = 1;var c = {};var combined = [].concat(a, b, c)combined; // ["string", 1, {…}]

4. Using Reduce method

The reduce() method executes a reducer function(that you provide) on each element of the array, resulting in a single output value. var array1 = [1,2,3,4,5];var array2 = [6,7,8,9,10];var array3 = array2.reduce((newArray, item) => { newArray.push(item); return newArray; ), array1);

merge 2 arrays into coordinates

yCord = [30, 29, 31, 32]; xCord = [0, 1, 2 ,3]; coords = xCord.map((i, index)=> [i, yCord[index]]); console.log(coords)

To list all arrays in JavaScript

One way is to put all arrays in an object Arrays = { house: ["red","blue","yellow"], cars: ["fast","big","safe"], sofa: ["cozy","modern","elegant"] } numberOfArrays = Object.keys(Arrays).length; sentence = numberOfArrays + ' Arrays - ' + Object.keys(Arrays).join(', '); var allListNames = ["longHistList", "myfavorList", "activeList", "aETFList", "ahDiffList", "a10YiList"] console.log(Array.from(allListNames));

onclick event

Note also: dblclick double-clicks on an element mousedown presses a mouse button over an element mouseup releases a mouse button over an element <p ondblclick="myFunction()">Double-click me</p> <p id="demo">Click me.</p> <script> document.getElementById("demo").onclick = function() {myFunction()}; function myFunction() { document.getElementById("demo").innerHTML = "YOU CLICKED ME!"; } </script> <button onclick="myFunction()">Try it</button> <p id="demo"></p> <script> function myFunction() { var person = prompt("Please enter your name", "Harry Potter"); if (person != null) { document.getElementById("demo").innerHTML = "Hello " + person + "! How are you today?"; } } </script>

Link Events

onClick onMouseOver onMouseOut (note the quotation marks arrangement!) <a href="index.htm" onMouseOver="home_button.src='homeon.gif';" onMouseOut="home_button.src='home.gif';"><img src="home.gif" alt="Home" name="home_button" border="0"></a> ===========================

Two JavaScripts most important functions, If and Loops.

var guess = prompt("Please guess a number between 1 and 10",""); if(guess == 5){ alert('Correct! I was thinking of 5');} else{ alert('Wrong! I was thinking of 5');} ===========================

Events

onBlur - Happens when the cursor is moved out of the field onFocus - Happens when the cursor is moved into the field onChange - Happens when the field is changed and the cursor moves out of it <input type="text" onBlur="dothis"> JavaScript Functions function sayhi() { alert(Hi there!); } } <a href="#" onMouseOver="sayhi();">Say Hi</a> ===========================

Submit Button

<form name="myform" onSubmit="return false;"> <input type="submit" value="Submit"> </form> <form name="myform" onSubmit="MyFunction(); return false;"> </fopre>

function getChar(event)

function getChar(event) { if (event.which!=0 && event.charCode!=0) { return String.fromCharCode(event.which) // the rest } else { return null // special key } } function openHtml(){ console.log( "keypress: " + $(this).value ); }; </script> <body onkeypress="chkKey()"> <!--<body onload="loadfile()">-->

onpagehide event

onpagehide event: navigates away from a webpage. Execute JavaScript code when the user navigates away from the document. The onpagehide event triggers in JavaScript when a user leaves the page and decides to move to another. Some examples include age refresh, a link is clicked, etc. the following code implement onpagehide event in JavaScript: ============ <body onpagehide="newFunc()"> <p>Close the page and see what happens!</p> <script>function newFunc() {alert("Thank you!"); } </script> </body> ============ jQuery pagehide Event To trigger the event for all pages in jQuery Mobile: $("document").on("pagehide",function(event){...}) To trigger the event for a specific page: $("document").on("pagehide","page",function(event,data){...}) <script> $(document).on("pagehide","#pagetwo",function(){alert("pagetwo is now hidden"); }); </script> ============ detect browser support for pageShow and pageHide if ('onpagehide' in window) { //if(window.onpagehide || window.onpagehide === null){window.addEventListener('pagehide', exitFunction, false); } else {window.addEventListener('unload', exitFunction, false); }

addEventListener

Attach a click event to the document. When the user clicks anywhere in the document: document.addEventListener("click", function(){ document.getElementById("demo").innerHTML = "Hello World"; }); window.onload = addfunc; document.getElementById('myBtn').onclick(){alert('hello');} document.getElementById('myBtn').addEventListener("click", funcname,false); document.getElementById('myBtn').attachEvent("onclick", funcname);

window.event, KeyboardEvent keyCode, which

function KeyPress(e){var keynum;if(window.event){keynum=e.keyCode;}else if(e.which){keynum=e.which;}if(keynum==13)sendme('oLGK__e.html',1); } window.event: Window Event Attributes keyCode: KeyboardEvent keyCode Property
KeyboardEvent which: KeyboardEvent which Property

Common HTML Events

Here is a list of some common HTML events: onchange An HTML element has been changed onclick The user clicks an HTML element onmouseover The user moves the mouse over an HTML element onmouseout The user moves the mouse away from an HTML element onkeydown The user pushes a keyboard key onload The browser has finished loading the page Common events There is a huge collection of events that can be generated by most element nodes: Mouse events. Keyboard events. HTML frame/object events. HTML form events. User interface events. Mutation events (notification of any changes to the structure of a document). Progress events). Note that the event classification above is not exactly the same as W3C's classification.
CategoryTypeAttributeDescriptionBubblesCancelable
MouseclickonclickFires when the pointing device button is clicked over an element. A click is defined as a mousedown and mouseup over the same screen location. The sequence of these events is: mousedown, mouseup, clickYesYes
dblclickondblclickFires when the pointing device button is double-clicked over an elementYesYes
mousedownonmousedownFires when the pointing device button is pressed over an elementYesYes
mouseuponmouseupFires when the pointing device button is released over an elementYesYes
mouseoveronmouseoverFires when the pointing device is moved onto an elementYesYes
mousemoveonmousemoveFires when the pointing device is moved while it is over an elementYesYes
mouseoutonmouseoutFires when the pointing device is moved away from an elementYesYes
dragstartondragstartFired on an element when a drag is started.YesYes
dragondragThis event is fired at the source of the drag, that is, the element where dragstart was fired, during the drag operation.YesYes
dragenterondragenterFired when the mouse is first moved over an element while a drag is occurring.YesYes
dragleaveondragleaveThis event is fired when the mouse leaves an element while a drag is occurring.YesNo
dragoverondragoverThis event is fired as the mouse is moved over an element when a drag is occurring.YesYes
dropondropThe drop event is fired on the element where the drop occurs at the end of the drag operation.YesYes
dragendondragendThe source of the drag will receive a dragend event when the drag operation is complete, whether it was successful or not.YesNo
KeyboardkeydownonkeydownFires before keypress, when a key on the keyboard is pressed.YesYes
keypressonkeypressFires after keydown, when a key on the keyboard is pressed.YesYes
keyuponkeyupFires when a key on the keyboard is releasedYesYes
HTML frame/objectloadonloadFires when the user agent finishes loading all content within a document, including window, frames, objects and images For elements, it fires when the target element and all of its content has finished loading NoNo
unloadonunloadFires when the user agent removes all content from a window or frame For elements, it fires when the target element or any of its content has been removed NoNo
abortonabortFires when an object/image is stopped from loading before completely loadedYesNo
erroronerrorFires when an object/image/frame cannot be loaded properlyYesNo
resizeonresizeFires when a document view is resizedYesNo
scrollonscrollFires when an element or document view is scrolledNo, except that a scroll event on document must bubble to the windowNo
HTML formselectonselectFires when a user selects some text in a text field, including input and textareaYesNo
changeonchangeFires when a control loses the input focus and its value has been modified since gaining focusYesNo
submitonsubmitFires when a form is submittedYesYes
resetonresetFires when a form is resetYesNo
focusonfocusFires when an element receives focus either via the pointing device or by tab navigationNoNo
bluronblurFires when an element loses focus either via the pointing device or by tabbing navigationNoNo
User interfacefocusin(none)Similar to HTML focus event, but can be applied to any focusable elementYesNo
focusout(none)Similar to HTML blur event, but can be applied to any focusable elementYesNo
DOMActivate(none)Similar to XUL command event. Fires when an element is activated, for instance, through a mouse click or a keypress.YesYes
MutationDOMSubtreeModified(none)Fires when the subtree is modifiedYesNo
DOMNodeInserted(none)Fires when a node has been added as a child of another nodeYesNo
DOMNodeRemoved(none)Fires when a node has been removed from a DOM-treeYesNo
DOMNodeRemovedFromDocument(none)Fires when a node is being removed from a documentNoNo
DOMNodeInsertedIntoDocument(none)Fires when a node is being inserted into a documentNoNo
DOMAttrModified(none)Fires when an attribute has been modifiedYesNo
DOMCharacterDataModified(none)Fires when the character data has been modifiedYesNo
Progressloadstart(none)Progress has begun.NoNo
progress(none)In progress. After loadstart has been dispatched.NoNo
error(none)Progression failed. After the last progress has been dispatched, or after loadstart has been dispatched if progress has not been dispatched.NoNo
abort(none)Progression is terminated. After the last progress has been dispatched, or after loadstart has been dispatched if progress has not been dispatched.NoNo
load(none)Progression is successful. After the last progress has been dispatched, or after loadstart has been dispatched if progress has not been dispatched.NoNo
loadend(none)Progress has stopped. After one of error, abort, or load has been dispatched.NoNo
Note that the events whose names start with "DOM" are currently not well supported, and for this and other performance reasons are deprecated by the W3C in DOM Level 3. Mozilla and Opera support DOMAttrModified, DOMNodeInserted, DOMNodeRemoved and DOMCharacterDataModified. Chrome and Safari support these events, except for DOMAttrModified.

Touch events

Web browsers running on touch-enabled devices, such as Apple's iOS and Google's Android, generate additional events.
CategoryTypeAttributeDescriptionBubblesCancelable
TouchtouchstartFires when a finger is placed on the touch surface/screen.YesYes
touchendFires when a finger is removed from the touch surface/screen.YesYes
touchmoveFires when a finger already placed on the screen is moved across the screen.YesYes
touchenterFires when a touch point moves onto the interactive area defined by a DOM element.YesYes
touchleaveFires when a touch point moves off the interactive area defined by a DOM element.YesYes
touchcancelA user agent must dispatch this event type to indicate when a TouchPoint has been disrupted in an implementation-specific manner, such as by moving outside the bounds of the UA window. A user agent may also dispatch this event type when the user places more touch points (The coordinate point at which a pointer (e.g. finger or stylus) intersects the target surface of an interface) on the touch surface than the device or implementation is configured to store, in which case the earliest TouchPoint object in the TouchList should be removed.YesNo
In the W3C draft recommendation, a TouchEvent delivers a TouchList of Touch locations, the modifier keys that were active, a TouchList of Touch locations within the targeted DOM element, and a TouchList of Touch locations that have changed since the previous TouchEvent. Apple didn't join this working group, and delayed W3C recommendation of its Touch Events Specification by disclosing patents late in the recommendation process.

Pointer events

Web browsers on devices with various types of input devices including mouse, touch panel, and pen may generate integrated input events. Users can see what type of input device is pressed, what button is pressed on that device, and how strongly the button is pressed when it comes to a stylus pen. As of October 2013, this event is only supported by Internet Explorer 10 and 11.
CategoryTypeAttributeDescriptionBubblesCancelable
PointerpointerdownonpointerdownFires when the pointing device button is activated, or pressed over an element.YesYes
pointeruponpointerupFires when the pointing device button is released over an elementYesYes
pointercancelonpointercancelFires when a pointing device is unlikely to continue to produce event because, for example, the device is used for panning/zooming after a pointerdown event.YesYes
pointermoveonpointermoveFires when the pointing device is moved while it is over an elementYesYes
pointeroveronpointeroverFires when the pointing device is moved onto an elementYesYes
pointeroutonpointeroutFires when the pointing device is moved away from an element. Also fires after pointerup by pointing device without hovering, or afterYesYes
pointerenteronpointerenterFires when the pointing device is moved onto an element, or when the button of the pointing device which does not support hovering is pressed on one of its descendant elements.NoYes
pointerleaveonpointerleaveFires when the pointing device is moved away from an element, or when the button of the pointing device which does not support hovering is released over its descendant elements.NoYes
gotpointercaptureongotpointercaptureFires when the pointer is captured by setPointerCapture method.YesNo
lostpointercaptureonlostpointercaptureFires when the pointer is released by releasePointerCapture method.YesNo

Indie UI events

Not yet really implemented, the Indie UI working groups want to help web application developers to be able to support standard user interaction events without having to handle different platform specific technical events that could match with it. Scripting usable interfaces can be difficult, especially when one considers that user interface design patterns differ across software platforms, hardware, and locales, and that those interactions can be further customized based on personal preference. Individuals are accustomed to the way the interface works on their own system, and their preferred interface frequently differs from that of the web application author's preferred interface. For example, web application authors, wishing to intercept a user's intent to undo the last action, need to "listen" for all the following events: Control+Z on Windows and Linux. Command+Z on Mac OS X. Shake events on some mobile devices. It would be simpler to listen for a single, normalized request to "undo" the previous action.
CategoryTypeDescriptionBubblesCancelable
RequestundorequestIndicates the user desires to "undo" the previous action. (May be superseded by the UndoManager interface.)YesYes
redorequestIndicates the user desires to "redo" the previously "undone" action. (May be superseded by the UndoManager interface.)Yesno
expandrequestIndicates the user desires to reveal information in a collapsed section (e.g. a disclosure widget) or branch node in a hierarchy (e.g., a tree view).YesYes
collapserequestIndicates the user desires to hide or collapse information in an expanded section (e.g. a disclosure widget) or branch node in a hierarchy (e.g., a tree view).YesYes
dismissrequestIndicates the user desires "dismiss" the current view (e.g. canceling a dialog, or closing a popup menu).YesYes
deleterequestIndicates the user wants to initiate a "delete" action on the marked element or current view.YesYes
Focus RequestdirectionalfocusrequestInitiated when the user agent sends a "direction focus" request to the web application. Web authors should not use or register for directionalfocusrequest events when standard browser focus and blur events are sufficient. Using these events unnecessarily could result in reduced performance or negative user experience.YesYes
linearfocusrequestInitiated when the user agent sends a "linear focus" request to the web application. Web authors should not use or register for linearfocusrequest events when standard browser focus and blur events are sufficient. This event type is only necessary on specialized control types such as data grids where the logical next element may not be focusable or even in the DOM until requested. Using these events unnecessarily could result in reduced performance or negative user experience.YesYes
palettefocusrequestInitiated when the user agent sends a "palette focus" request to the web application. Web app authors receiving this event should move focus to the first palette in the web application, or cycle focus between all available palettes. Note: palettes are sometimes referred to as non-modal dialogs or inspector windows.YesYes
toolbarfocusrequestInitiated when the user agent sends a "toolbar focus" request to the web application. Web app authors receiving this event should move focus to the main toolbar in the web application, or cycle focus between all available toolbars.YesYes
Manipulation RequestmoverequestInitiated when the user agent sends a move request to the web application with accompanying x/y delta values. This is used, for example, when moving an object to a new location on a layout canvas.YesYes
panrequestInitiated when the user agent sends a pan request to the web application with accompanying x/y delta values. This is used, for example, when changing the center point while panning a map or another custom image viewer.YesYes
rotationrequestInitiated when the user agent sends a rotation request to the web application with accompanying origin x/y values and a rotation value in degrees.YesYes
zoomrequestInitiated when the user agent sends a zoom request to the web application with accompanying origin x/y values and the zoom scale factor.YesYes
Scroll RequestscrollrequestInitiated when the user agent sends a scroll request to the web application with accompanying x/y delta values or one of the other defined scrollType values. Authors should only use this event and uiaction with custom scroll views.YesYes
ValueChange RequestvaluechangerequestInitiated when the user agent sends a value change request to the web application. Used on custom range controls like sliders, carousels, etc.YesYes

Internet Explorer-specific events

In addition to the common (W3C) events, two major types of events are added by Internet Explorer. Some of the events have been implemented as de facto standards by other browsers. Clipboard events. Data binding events.
CategoryTypeAttributeDescriptionBubblesCancelable
ClipboardcutoncutFires after a selection is cut to the clipboard.YesYes
copyoncopyFires after a selection is copied to the clipboard.YesYes
pasteonpasteFires after a selection is pasted from the clipboard.YesYes
beforecutonbeforecutFires before a selection is cut to the clipboard.YesYes
beforecopyonbeforecopyFires before a selection is copied to the clipboard.YesYes
beforepasteonbeforepasteFires before a selection is pasted from the clipboard.YesYes
Data bindingafterupdateonafterupdateFires immediately after a databound object has been updated.YesNo
beforeupdateonbeforeupdateFires before a data source is updated.YesYes
cellchangeoncellchangeFires when a data source has changed.YesNo
dataavailableondataavailableFires when new data from a data source become available.YesNo
datasetchangedondatasetchangedFires when content at a data source has changed.YesNo
datasetcompleteondatasetcompleteFires when transfer of data from the data source has completed.YesNo
errorupdateonerrorupdateFires if an error occurs while updating a data field.YesNo
rowenteronrowenterFires when a new row of data from the data source is available.YesNo
rowexitonrowexitFires when a row of data from the data source has just finished.NoYes
rowsdeleteonrowsdeleteFires when a row of data from the data source is deleted.YesNo
rowinsertedonrowinsertedFires when a row of data from the data source is inserted.YesNo
MousecontextmenuoncontextmenuFires when the context menu is shown.YesYes
dragondragFires when during a mouse drag (on the moving Element).YesYes
dragstartondragstartFires when a mouse drag begins (on the moving Element).YesYes
dragenterondragenterFires when something is dragged onto an area (on the target Element).YesYes
dragoverondragoverFires when a drag is held over an area (on the target Element).YesYes
dragleaveondragleaveFires when something is dragged out of an area (on the target Element).YesYes
dragendondragendFires when a mouse drag ends (on the moving Element).YesYes
dropondropFires when a mouse button is released over a valid target during a drag (on the target Element).YesYes
selectstartonselectstartFires when the user starts to select text.YesYes
KeyboardhelponhelpFires when the user initiates help.YesYes
HTML frame/objectbeforeunloadonbeforeunloadFires before a document is unloaded.NoYes
stoponstopFires when the user stops loading the object. (unlike abort, stop event can be attached to document)NoNo
HTML formbeforeeditfocusonbeforeeditfocusFires before an element gains focus for editing.YesYes
MarqueestartonstartFires when a marquee begins a new loop.NoNo
finishonfinishFires when marquee looping is complete.NoYes
bounceonbounceFires when a scrolling marquee bounces back in the other direction.NoYes
MiscellaneousbeforeprintonbeforeprintFires before a document is printedNoNo
afterprintonafterprintFires immediately after the document prints.NoNo
propertychangeonpropertychangeFires when the property of an object is changed.NoNo
filterchangeonfilterchangeFires when a filter changes properties or finishes a transition.NoNo
readystatechangeonreadystatechangeFires when the readyState property of an element changes.NoNo
losecaptureonlosecaptureFires when the releaseCapture method is invoked.NoNo
Note that Mozilla, Safari and Opera also support the readystatechange event for the XMLHttpRequest object. Mozilla also supports the beforeunload event using the traditional event registration method (DOM Level 0). Mozilla and Safari also support contextmenu, but Internet Explorer for Mac does not. Note that Firefox 6 and later support the beforeprint and afterprint events.

XUL events

In addition to the common (W3C) events, Mozilla defined a set of events that work only with XUL elements.
CategoryTypeAttributeDescriptionBubblesCancelable
MouseDOMMouseScrollDOMMouseScrollFires when the mouse wheel is moved, causing the content to scroll.YesYes
dragdropondragdropFires when the user releases the mouse button to drop an object being dragged.NoNo
dragenterondragenterFires when the mouse pointer first moves over an element during a drag. It is similar to the mouseover event but occurs while dragging.NoNo
dragexitondragexitFires when the mouse pointer moves away from an element during a drag. It is also called after a drop on an element. It is similar to the mouseout event but occurs during a drag.NoNo
draggestureondraggestureFires when the user starts dragging the element, usually by holding down the mouse button and moving the mouse.NoNo
dragoverondragoverRelated to the mousemove event, this event is fired while something is being dragged over an element.NoNo
InputCheckboxStateChangeFires when a checkbox is checked or unchecked, either by the user or a script.NoNo
RadioStateChangeFires when a radio button is selected, either by the user or a script.NoNo
closeoncloseFires when a request has been made to close the window.NoYes
commandoncommandSimilar to W3C DOMActivate event. Fires when an element is activated, for instance, through a mouse click or a keypress.NoNo
inputoninputFires when a user enters text in a textbox.YesNo
User interfaceDOMMenuItemActiveDOMMenuItemActiveFires when a menu or menuitem is hovered over, or highlighted.YesNo
DOMMenuItemInactiveDOMMenuItemInactiveFires when a menu or menuitem is no longer being hovered over, or highlighted.YesNo
contextmenuoncontextmenuFires when the user requests to open the context menu for the element. The action to do this varies by platform, but it will typically be a right click.NoYes
overflowonoverflowFires a box or other layout element when there is not enough space to display it at full size.NoNo
overflowchangedonoverflowchangedFires when the overflow state changes.NoNo
underflowonunderflowFires to an element when there becomes enough space to display it at full size.NoNo
popuphiddenonpopuphiddenFires to a popup after it has been hidden.NoNo
popuphidingonpopuphidingFires to a popup when it is about to be hidden.NoNo
popupshowingonpopupshowingFires to a popup just before it is popped open.NoYes
popupshownonpopupshownFires to a popup after it has been opened, much like the onload event is sent to a window when it is opened.NoNo
CommandbroadcastonbroadcastPlaced on an observer. The broadcast event is sent when the attributes of the broadcaster being listened to are changed.NoNo
commandupdateoncommandupdateFires when a command update occurs.NoNo

Other events

For Mozilla and Opera 9, there are also undocumented events known as DOMContentLoaded and DOMFrameContentLoaded which fire when the DOM content is loaded. These are different from "load" as they fire before the loading of related files (e.g., images). However, DOMContentLoaded has been added to the HTML 5 specification. The DOMContentLoaded event was also implemented in the Webkit rendering engine build 500+. Opera 9 also supports the Web Forms 2.0 events DOMControlValueChanged, invalid, forminput and formchange.

Event flow

Consider the situation when there are 2 elements nested together. Both have event handlers registered on the same event type, say "click". When the user clicks on the inner element, there are two possible ways to handle it: Trigger the elements from outer to inner (event capturing). This model is implemented in Netscape Navigator. Trigger the elements from inner to outer (event bubbling). This model is implemented in Internet Explorer and other browsers. W3C takes a middle position in this struggle. Events are first captured until it reaches the target element, and then bubbled up. During the event flow, an event can be responded to at any element in the path (an observer) in either phase by causing an action, and/or by stopping the event (with method event.stopPropagation() for W3C-conforming browsers and command event.cancelBubble = true for Internet Explorer), and/or by cancelling the default action for the event.

Event object

The Event object provides a lot of information about a particular event, including information about target element, key pressed, mouse button pressed, mouse position, etc. Unfortunately, there are very serious browser incompatibilities in this area. Hence only the W3C Event object is discussed in this article.
Event properties
NameTypeDescription
typeDOMStringThe name of the event (case-insensitive in DOM level 2 but case-sensitive in DOM level 3 ).
targetEventTargetUsed to indicate the EventTarget to which the event was originally dispatched.
currentTargetEventTargetUsed to indicate the EventTarget whose EventListeners are currently being processed.
eventPhaseunsigned shortUsed to indicate which phase of event flow is currently being evaluated.
bubblesbooleanUsed to indicate whether or not an event is a bubbling event.
cancelablebooleanUsed to indicate whether or not an event can have its default action prevented.
timeStampDOMTimeStampUsed to specify the time (in milliseconds relative to the epoch) at which the event was created.
Event methods
NameArgument typeArgument nameDescription
stopPropagationTo prevent further propagation of an event during event flow.
preventDefaultTo cancel the event if it is cancelable, meaning that any default action normally taken by the implementation as a result of the event will not occur.
initEventDOMStringeventTypeArgSpecifies the event type.
booleancanBubbleArgSpecifies whether or not the event can bubble.
booleancancelableArgSpecifies whether or not the event's default action can be prevented.

The onreadystatechange Event

The readyState property holds the status of the XMLHttpRequest. The onreadystatechange event is triggered every time the readyState changes. During a server request, the readyState changes from 0 to 4: 0: request not initialized
1: server connection established
2: request received
3: processing request
4: request finished and response is ready In the onreadystatechange property, specify a function to be executed when the readyState changes: xhttp.onreadystatechange = function() When readyState is 4 and status is 200, the response is ready: if (this.readyState == 4 && this.status == 200)

POPUP Message using Event:

Display a simple message "Welcome!!!" on your demo webpage and when the user hovers over the message, a popup should be displayed with a message "Welcome to my WebPage!!!". Solution: <html><head><title>Event!!!</title><script type="text/javascript">function trigger(){document.getElementById("hover").addEventListener("mouseover", popup);function popup(){alert("Welcome to my WebPage!!!");}}</script><style>p{ font-size:50px; position: fixed; left: 550px; top: 300px;}</style></head><body onload="trigger();"><p id="hover">Welcome!!!</p></body></html>

What about Events?

JavaScript is an event-driven programming language. We also use callback functions for event declarations. For example, let’s say we want users to click on a button: <button>Click here</button> This time we will see a message on the console only when the user clicks on the button: document.queryselector("#callback-btn") .addEventListener("click", function() { console.log("User has clicked on the button!"); }); So here we select the button first with its id, and then we add an event listener with the addEventListener method. It takes 2 parameters. The first one is its type, “click”, and the second parameter is a callback function, which logs the message when the button is clicked. As you can see, callback functions are also used for event declarations in JavaScript.

KeyboardEvent ctrlKey Property

event.ctrlKey true - The ctrl key was pressed false - The ctrl key was not pressed if (event.ctrlKey) { alert('ctrl yes'); } else { alert('ctrl no'); }

KeyboardEvent shiftKey Property

event.shiftKey if (event.shiftKey) { alert('shift yes'); } else { alert('shift no'); }

KeyboardEvent metaKey Property

event.metaKey if (event.metaKey) { alert('metaKey yes'); } else { alert('metaKey no'); }

KeyboardEvent keyCode Property

event.keyCode var x = event.keyCode; <input type="text" onkeypress="uniCharCode(event)" onkeydown="uniKeyCode(event)"> // both function will be called at the same time when key pressed function uniCharCode(event) { var char = event.which || event.keyCode; alert("Unicode CHARACTER code: " + char); } function uniKeyCode(event) { var key = event.keyCode; alert('Unicode KEY code: " + key); } When pressing the "a" key on the keyboard (not using caps lock), the result of char and key will be: Unicode CHARACTER code: 97 Unicode KEY code: 65 Example Alert some text if the user presses the Escape key: <input type="text" onkeydown="myFunction(event)"> function myFunction(event) { var x = event.keyCode; if (x == 27) { // 27 is the ESC key alert ("You pressed the Escape key!"); } } Example Convert the Unicode value into a character (does not work for function keys): var x = event.keyCode; // Get the Unicode value var y = String.fromCharCode(x); // Convert the value into a character

KeyboardEvent which Property

event.which returns the Unicode character code of the key that triggered the onkeypress event, or the Unicode key code of the key that triggered the onkeydown or onkeyup event. Example Get the Unicode value of the pressed keyboard key: var x = event.which;

KeyboardEvent key Property

event.key A String, representing the pressed keyboard button. Possible values: A single character (like "a", "W", "4", "+" or "$") A multicharacter (like "F1", "Enter", "HOME" or "CAPS LOCK") Example Alert some text if the user presses the "A" key: var x = event.key; // If the pressed keyboard button is "a" or "A" (using caps lock or shift), alert some text. if (x == "a" || x == "A") { alert ("You pressed the 'A' key!"); }

KeyboardEvent charCode Property

event.charCode A Number, representing the Unicode character code Example Alert some text if the user presses the "O" key: function myFunction(event) { var x = event.charCode || event.keyCode; if (x == 111 || x == 79) { // o is 111, O is 79 alert("You pressed the 'O' key!"); } }

onwheel, onscroll Event

onwheel specifically fires when the mouse wheel is spun. Note that onwheel is non-standard and should be avoided unless you're specifically targeting browsers that support it and/or are providing an extra feature whose absence won't be felt. onscroll fires for any kind of scrolling, including keyboard buttons like the arrow keys, Home, End, Page Up, Page Down, space bar, tabbing etc. object.onscroll = function(){myScript}; using the addEventListener() method: object.addEventListener("scroll", myScript); Note: The addEventListener() method is not supported in Internet Explorer 8 and earlier versions. Example Toggle between class names on different scroll positions - When the user scrolls down 50 pixels from the top of the page, the class name "test" will be added to an element (and removed when scrolled up again). window.onscroll = function() {myFunction()}; function myFunction() { if (document.body.scrollTop > 50 || document.documentElement.scrollTop > 50) { document.getElementById("myP").className = "test"; } else { document.getElementById("myP").className = ""; } } window.onscroll function up = document.getElementById("BackToTop2"); window.onscroll = function() { scrollFunction() }; function scrollFunction() { if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 100) { up.style.display = "block"; } else { up.style.display = "none"; } } function topFunction() { document.body.scrollTop = 0; document.documentElement.scrollTop = 0; } Example Slide in an element when the user has scrolled down 350 pixels from the top of the page (add the slideUp class): window.onscroll = function() {myFunction()}; function myFunction() { if (document.body.scrollTop > 350 || document.documentElement.scrollTop > 350) { document.getElementById("myImg").className = "slideUp"; } } // 滚屏时触发函数 window.onscroll =function(){ lazyload(imgs); }

MouseEvent which Property

event.which returns a number that indicates which mouse button was pressed when a mouse event was triggered. Example Find out which mouse button that was pressed when a mouse event was triggered: alert("You pressed button: " + event.which)

MouseEvent button Property

event.button A Number, representing which mouse button that was pressed when the mouse event occured. alert("You pressed button: " + event.button)

All HTML DOM Event, Properties, and Methods

All HTML DOM Event, Properties, and Methods Events are normally used in combination with functions

pass event as argument to an inline event handler

to pass the event object: <p id="p" onclick="doSomething(event)"> to get the clicked child element (should be used with event parameter: function doSomething(e) { e = e || window.event; var target = e.target || e.srcElement; console.log(target); } to pass the element itself (DOMElement): <p id="p" onclick="doThing(this)"> Since inline events are executed as functions you can simply use arguments. <p id="p" onclick="doSomething.apply(this, arguments)"> and function doSomething(e) { if (!e) e = window.event; // 'e' is the event. // 'this' is the P element } You don't need to pass this, there already is the event object passed by default automatically, which contains event.target which has the object it's coming from. You can lighten your syntax: This: <p onclick="doSomething()">aaaa</p> Will work with this: function doSomething(){ console.log(event); console.log(event.target); }

The e is short for event

The simplest way to create an event is to click somewhere on the page. When you click, a click event is triggered. This event is actually an object containing information about the action that just happened. Now, events happen all the time, however you are not interested in all the events that happen. When you are interested in some event however, it's when you add an event listener to the element you know will create events. For example you are interested in knowing when the user clicks on a 'Subscribe' button and you want to do something when this event happens. In order to do something about this event you bind an event handler to the button you are interested in. The way to bind the handler to the element is by doing element.addEventListener(eventName, handler). eventName is a string and it's the name of the event you are interested in, in this case that would be 'click' (for the click event). The handler is simply a function which does something (it's executed) when the event happens. The handler function, by default, when executed is passed the event object (that was created when the event/action you are interested in happened) as an argument. Defining the event as a parameter of your handler function is optional but, sometimes (most times), it is useful for the handler function to know about the event that happened. When you do define it this is the e you see in the functions like the ones you mentioned. Remember, the event is just a regular javascript object, with lots of properties on it.

variables in event handler using function closures

function addClickHandler(elem, arg1, arg2) { elem.addEventListener('click', function(e) { // in the event handler function here, you can directly refer // to arg1 and arg2 from the parent function arguments }, false); } element.addEventListener('click', func(event, this.elements[i])) element.addEventListener('click', (function(passedInElement) { return function(e) {func(e, passedInElement); }; }) (this.elements[i]), false); // return our event handler while capturing an argument in the closure function handleEvent(passedInElement) { return function(e) { func(e, passedInElement); }; } element.addEventListener('click', handleEvent(this.elements[i]));

Guide To Server-Sent Events

https://www.html5rocks.com/en/tutorials/eventsource/basics/
Server-Sent Events,  The API,  Server-Side Implementation,  Client-Side Implementation,  Putting It All Together,  Custom Event Types,  Auto Reconnect,  Last-Event-Id Header,  Browser Support,  Sever-Sent Events vs. WebSockets,  
When it comes to developing an application that enables real-time operations, the first thing that comes to mind is WebSockets, which is fine, but there are other options that need to be considered. One of them is Server-Sent Events, which enable a unidirectional communication flow between server and client.

Server-Sent Events

Server-Sent Events is a server push technology that allows a client to receive automatic updates from the server via an HTTP connection. They are very easy to implement, but there are some important things you should know before choosing them for your application:
  • The technology is based on the plain HTTP
  • Allows only unidirectional data flow (as already mentioned)
  • It is limited to pure text data, no binaries allowed
  • The API

    The Server-Sent Event API is contained in the EventSource interface.

    Open a connection (same domain)

    To open the connection to a server, create a new EventSource object with the URL of the script that generates the events: const eventSource = new EventSource("/api/events");

    Open a connection (other domain)

    If the URL passed to the EventSource is on the other domain, a second parameter can be specified and a withCredentials property can be set to true, which means that the Cookie will be sent together: const eventSource = new EventSource("http://localhost:8000/api/events", { withCredentials: true });

    Listen for messages

    Once the connection is instantiated, we need to listen to the events coming from the server: eventSource.addEventListener("message", (event) => { // "event.data" is a string const data = JSON.parse(event.data); // Prints whatever was sent by the server console.log(data); }); Important note: As the server only sends text data, we have to stringify it on the server-side and parse it on the client.

    Listen for errors

    If an error occurs (network timeout or something), an error event is generated and we can listen for it: eventSource.addEventListener("error", (error) => { // Prints the information about an error console.log(error); });

    Listen for an open connection

    When the connection is opened, an open event is generated and we can listen for it as well: eventSource.addEventListener("open", (event) => { // Prints the information about an event console.log(event); });

    Check the state of the connection

    The state of the connection is stored in the readyState property of the EventSource:
  • 0 - EventSource.CONNECTING
  • 1 - EventSource.OPEN
  • 2 - EventSource.CLOSED
  • const connectionState = eventSource.readyState;

    Close the connection

    When the connection between the server and the client interrupts, it is automatically restarted. However, it can be terminated with the close method: eventSource.close();

    Server-Side Implementation

    To establish a connection with the client, we have to send 200 status code together with the Content-Type: text/event-stream and Connection: keep-alive headers. Let's take a look at the complete example with Node.js and explain each line of code in the comment above: const express = require("express"); const bodyParser = require("body-parser"); const cors = require("cors"); const app = express(); const PORT = 3000; // Store all connected clients let clients = []; const addSubscriber = (req, res) => { // Set necessary headers to establish a stream of events const headers = { "Content-Type": "text/event-stream", Connection: "keep-alive", }; res.writeHead(200, headers); // Add a new client that just connected // Store the id and the whole response object const id = Date.now(); const client = { id, res, }; clients.push(client); console.log(`Client connected: ${id}`); // When the connection is closed, remove the client from the subscribers req.on("close", () => { console.log(`Client disconnected: ${id}`); clients = clients.filter((client) => client.id !== id); }); }; const notifySubscribers = (message) => { // Send a message to each subscriber clients.forEach((client) => client.res.write(`data: ${JSON.stringify(message)}\n\n`) ); }; // Add a new message and send it to all subscribed clients const addMessage = (req, res) => { const message = req.body; // Return the message as a response for the "/message" call res.json(message); return notifySubscribers(message); }; // Get a number of the clients subscribed const getSubscribers = (_req, res) => { return res.json(clients.length); }; app.use(cors()); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); // Define endpoints app.get("/subscribe", addSubscriber); app.post("/message", addMessage); app.get("/status", getSubscribers); // Start the app app.listen(PORT, () => { console.log(`App listening on port ${PORT}`); }); The main purpose of this code is to track all connected clients and inform them about the data sent to the /message endpoint. Important note: \n does a line break. \n\n means the end of the message, do not forget to add that.

    Client-Side Implementation

    On the client-side, we create a simple React component using the EventSource API to connect to the event stream and display the real-time data: const App = () => { const [data, setData] = useState([]); useEffect(() => { // Subscribe to the event stream const eventSource = new EventSource("http://localhost:3000/subscribe"); eventSource.addEventListener("message", handleReceiveMessage); return () => { // Remove event listener and close the connection on unmount eventSource.removeEventListener("message", handleReceiveMessage); eventSource.close(); }; }, []); // Get the message and store it in the state const handleReceiveMessage = (event: any) => { const eventData = JSON.parse(event.data); setData((data) => data.concat(eventData)); }; // Send 5 random chars to the server const handleSendMessage = () => { axios.post("http://localhost:3000/message", { message: generateRandomChars(5), }); }; return ( <div style={{ padding: "0 20px" }}> <div> <h4>Click to send a message</h4> <button onClick={handleSendMessage}>Send</button> </div> <div> <h4>Message List</h4> <p>Number of messages: {data.length}</p> {data.map((item, index) => ( <div key={index}>{item.message}</div> ))} </div> </div> ); };

    Putting It All Together

    To see our example in action, start the client (your start script may look different): yarn start And the server: node server.js You should see the app running: Client-Side App And the server: Server-Side App Notice the log Client connected: 1607163222261 which means that the connection has been established and we can use the channel to send events. Click on the Send button on the UI (which POSTs 5 random characters to the /message endpoint) and notice how they appear in the list: Working App

    Custom Event Types

    The default event type used by Server-Sent Events is a message. A custom event can be sent by specifying the event at the start: client.res.write(`event: join\ndata: ${JSON.stringify(message)}\n\n`); And then the client can listen for this event: eventSource.addEventListener("join", handleReceiveMessage);

    Auto Reconnect

    If the server crashes or the connection is lost, the EventSource tries to reconnect, we do not need to worry about it. There is usually a delay of a few seconds between reconnections: Auto Reconnect The server can specify a recommended delay by specifying the retry at the beginning of an event: // Retry each 5 seconds client.res.write(`retry:5000\ndata: ${JSON.stringify(message)}\n\n`); If the browser knows that there is no Internet connection at the moment, it will try again to reconnect once the Internet connection is established.

    Last-Event-Id Header

    It is essential that the connection is resumed at the same point where it was interrupted so that no messages are lost. This can be achieved with the Last-Event-Id header, which is automatically added when a certain condition is met. Each message from the server should contain a unique id field: client.res.write(`data: ${JSON.stringify(message)}\nid:500\n\n`); When the browser receives a message with a set id, it sets the eventSource.lastEventId property to its value and sends this value in the Last-Event-Id header when reconnected: Last-Event-Id header Important note: the id should be appended by the server after the data to ensure that the eventSource.lastEventId is updated after the message is received.

    Browser Support

    According to caniuse, Server-Sent Events are available for more than 96% of the users as of 06.12.2020: Browser Support Image The following code can be used to check if the browser supports the feature: if ("EventSource" in window) { // Implement it }

    Sever-Sent Events vs. WebSockets

    The WebSocket protocol enables the exchange of events between the server and the client. The data can be sent in both directions. What are the main differences between the two technologies?
  • Server-Sent Events are based on HTTP, WebSockets on the WebSocket protocol
  • Server-Sent Events do not allow bidirectional data flow, WebSockets do
  • Server-Sent Events do not allow sending binary data, WebSockets do
  • Server-Sent Events provide an automatic reconnection if the connection is lost, WebSockets do not (you have to implement it manually)
  • Server-Sent Events have a limited maximum number of open connections (6), which can be painful if you need to open more tabs, WebSockets have no limitations
  • When you see all these disadvantages of using Server-Sent Events, are they really a competitor to WebSockets? They are much easier and faster to implement. So if you need a quick way to set up the real-time unidirectional communication between server and client and are aware of all the potential risks, this is the best way to go. However, be aware that there is a high probability that the solution will eventually be refactored to the WebSockets.

    Server-Sent Events - One Way Messaging

    A server-sent event is when a web page automatically gets updates from a server. This was also possible before, but the web page would have to ask if any updates were available. With server-sent events, the updates come automatically.

    Receive Server-Sent Event Notifications

    The EventSource object is used to receive server-sent event notifications: Example var source = new EventSource("demo_sse.php"); source.onmessage = function(event) { document.getElementById("result").innerHTML += event.data + "
    "; }; Example explained: Create a new EventSource object, and specify the URL of the page sending the updates (in this example "demo_sse.php") Each time an update is received, the onmessage event occurs When an onmessage event occurs, put the received data into the element with id="result" <!DOCTYPE html> <html> <body> <h1>Getting server updates</h1> <div id="result"></div> <script> if(typeof(EventSource) !== "undefined") { var source = new EventSource("demo_sse.php"); source.onmessage = function(event) { document.getElementById("result").innerHTML += event.data + "<br>"; }; } else { document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events..."; } </script> </body> </html>

    Check Server-Sent Events Support

    In the tryit example above there were some extra lines of code to check browser support for server-sent events: if(typeof(EventSource) !== "undefined") { // Yes! Server-sent events support! // Some code..... } else { // Sorry! No server-sent events support.. }

    Server-Side Code Example

    For the example above to work, you need a server capable of sending data updates (like PHP or ASP). The server-side event stream syntax is simple. Set the "Content-Type" header to "text/event-stream". Now you can start sending event streams. Code in PHP (demo_sse.php): Code in ASP (VB) (demo_sse.asp): <% Response.ContentType = "text/event-stream" Response.Expires = -1 Response.Write("data: The server time is: " & now()) Response.Flush() %> Code explained: Set the "Content-Type" header to "text/event-stream" Specify that the page should not cache Output the data to send (Always start with "data: ") Flush the output data back to the web page The EventSource Object In the examples above we used the onmessage event to get messages. But other events are also available: Events Description onopen When a connection to the server is opened onmessage When a message is received onerror When an error occurs

    Using Chrome JavaScript Debugger to break on page loading events

    https://stackoverflow.com/questions/6727370/using-chrome-javascript-debugger-how-to-break-on-page-loading-events https://developer.chrome.com/docs/devtools/javascript/breakpoints/#event-listeners In Chrome's Developer Tools, go to the Sources tab. On the right, open up Event Listener Breakpoints, and you can set breakpoints on events. It sounds as if you'll want to set your breakpoint on DOMContentLoaded, which is under the DOM Mutation section. After you do this, reload the page and you'll end up in the debugger.

    load an external Javascript file during an "onclick" event

    Use jQuery's $.getScript() function sample code: $("button").click(function(){ $.getScript("demo_ajax_script.js"); }); has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, isolated-app

    Custom Events

    Introduction to JavaScript custom events
    Creating JavaScript custom events
    Dispatching JavaScript custom events
    JavaScript custom event example
    Why use custom events


    Introduction to JavaScript custom events

    The following function highlights an element by changing its background color to yellow: function highlight(elem) { const bgColor = 'yellow'; elem.style.backgroundColor = bgColor; } To execute a piece of code after highlighting the element, you may come up with a callback: function highlight(elem, callback) { const bgColor = 'yellow'; elem.style.backgroundColor = bgColor; if(callback && typeof callback === 'function') { callback(elem); } } The following calls the highlight() function and adds a border to a <div> element: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JS Custom Event Demo</title> </head> <body> <div>JS Custom Event Demo</div> <script> function highlight(elem, callback) { const bgColor = 'yellow'; elem.style.backgroundColor = bgColor; if (callback && typeof callback === 'function') { callback(elem); } } let note = document.querySelector('.note'); function addBorder(elem) { elem.style.border = "solid 1px red"; } highlight(note, addBorder); </script> </body> </html>Code language: HTML, XML (xml) To make the code more flexible, you can use the custom event.

    Creating JavaScript custom events

    To create a custom event, you use the CustomEvent() constructor: let event = new CustomEvent(eventType, options); The CustomEvent() has two parameters: The eventType is a string that represents the name of the event. The options is an object has the detail property that contains any custom information about the event. The following example shows how to create a new custom event called highlight: let event = new CustomEvent('highlight', { detail: {backgroundColor: 'yellow'} });

    Dispatching JavaScript custom events

    After creating a custom event, you need to attach the event to a DOM element and trigger it by using the dispatchEvent() method: domElement.dispatchEvent(event);

    JavaScript custom event example

    Put it all together: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JavaScript Custom Event</title> </head> <body> <div>JS Custom Event</div> <script> function highlight(elem) { const bgColor = 'yellow'; elem.style.backgroundColor = bgColor; // create the event let event = new CustomEvent('highlight', { detail: { backgroundColor: bgColor } }); // dispatch the event elem.dispatchEvent(event); } // Select the div element let div = document.querySelector('.note'); // Add border style function addBorder(elem) { elem.style.border = "solid 1px red"; } // Listen to the highlight event div.addEventListener('highlight', function (e) { addBorder(this); // examine the background console.log(e.detail); }); // highlight div element highlight(div); </script> </body> </html>Code language: HTML, XML (xml) How it works: First, declare the highlight() function that highlights an element and triggers the highlight event. Second, select the <div> element by using the querySelector() method. Third, listen to the highlight event. Inside the event listener, call the addBorder() function and show the detail property in the Console. Finally, call the highlight() function that will trigger the highlight event.

    Why use custom events

    Custom events allow you to decouple code execution, allowing one piece of code to run after another completes. For example, you can place event listeners in a separate script file and have multiple listeners for the same custom event. 自定义事件 CustomEvent 使用自定义事件可以很好地解耦组件间通信依赖,便于实现组件的高内聚低耦合。 1. 创建自定义事件 通过 CustomEvent 构造函数来创建一个新的自定义事件的实例: const event = new CustomEvent('myEvent', { detail: { message: 'Hello, this is a custom event!', // Add other properties }, bubbles: true, // 是否冒泡 cancelable: true, // 是否可以取消 }); 参数说明: a.事件名称 - 该参数是必填项,是事件的名称,监听事件是通过该名称进行监听器的挂载。 b.事件初始化对象 - 该参数是可选项,表示传递出去的事件内容。有以下属性: detail - 消息体内容 bubbles - 是否冒泡 cancelable - 是否可取消 2. 事件监听 通过元素的 addEventListener 方法进行事件处理函数的监听注册。 // 监听自定义事件 element.addEventListener('myEvent', function(e) { console.log(e.detail.message); }); 3. 事件触发 通过元素的 dispatchEvent 方法来在指定的元素上触发一个事件。 const element = document.getElementById('myElement'); // 触发事件 element.dispatchEvent(event); 4. 自定义事件的应用 - 组件间通信 组件间通信可以使用 props 传递 handler 的方式让子组件发生变化的时候通知父组件,或者使用全局状态管理的库进行组件间通信。 但是 props 传递 handler 的方式仅限于父子组件间通信,如果涉及多级组件,那就会涉及handler传递的问题。 在不引入第三方库(如 Redux)的情况下,使用自定义事件是一个不错的组件间通信的方法,也可以很好地解耦组件的依赖。 在下面的React例子中,在一个页面上有定义了两个组件,分别是 OrderList 和 OrderDetailPanel. OrderList 展示一个订单列表,每一行订单信息有一个按钮,点击按钮表示选中该订单。 而 OrderDetailPanel 组件就会显示选中的订单内容。 import React, { useState, useEffect } from 'react'; // 组件1: 订单列表 function OrderList({ orderList }) { const notifyOrderSelected = (id) => { // 新建一个自定义事件,把选中的订单信息通过事件进行携带出去 const event = new CustomEvent('order-selected', { detail: { id } }); // 发布事件给监听者 window.dispatchEvent(event); }; return ( <> {orderList.map((order) => ( <div> <span>{order.description}</span> <button onClick={() => notifyOrderSelected(order.id)}>选择</button> </div> ))} </> ); } // 组件2: 订单详情信息 function OrderDetailPanel() { const [orderId, setOrderId] = useState(); useEffect(() => { const handleOrderSelected = (event) => { setOrderId(event.detail.id); }; // 监听订单选中事件 window.addEventListener('order-selected', handleOrderSelected); // 组件卸载的时候清除监听器 return () => window.removeEventListener('order-selected', handleOrderSelected); }, []); return <>Selected Order is {orderId}</>; } 这样的话,OrderList组件和OrderDetailPanel组件就不需要知道对方的存在,只需要知道有一个 order-selected 事件即可。 当我们再加入另一个新组件用于展示选中订单的评论列表的时候,就可以新加一个 OrderComments 组件去监听 order-selected 事件,拉取订单评论进行展示。无须关注OrderList和其他组件的存在。

    alert() and prompt()

    alert(message) // use this to alert variable inside string function doHomework(subject) { alert(`Starting my ${subject} homework.`); } doHomework('math'); // Alerts: Starting my math homework. prompt(text, defaultText) text text to display in the dialog box defaults Optional. The default input text confirm(message) returns true if the user clicked "OK", and false otherwise.

    Opening A Window

    Browser Windows <a href="link.html" target="mywindow">Click Here</a> Opening A Window With JavaScript window.open('link.html','mywindow'); onclick <a href="#" onClick="window.open('link.html','mywindow');">Click Here</a> Manipulating Windows features window.open('link.html','mywindow','window features'); ===========================

    password

    var password = 'hello'; var input = prompt('Please enter the password', ''); while(input != password){var input= prompt('Please enter the password','');}

    for loop

    different kinds of loops: for - loops through a block of code a number of times for/in - loops through the properties of an object for/of - loops through the values of an iterable object while - loops through a block of code while a specified condition is true do/while - also loops through a block of code while a specified condition is true for loop for(loop=0; loop < 11; loop++){ document.writeln(loop);}

    The For/In Loop

    <div id="log"></div> var person = {fname:"John", lname:"Doe", age:25}; var text = ""; var x; for (x in person) { text += person[x]+" "; $("#log").append(x, ": ") $("#log").append(person[x], ",
    ") } $("#log").append("
    ",text) Efficient way of getting an object's keys using an expression within the for-in loop's conditions var myObj = {a: 1, b: 2, c:3}, myKeys = [], i=0; for (myKeys[i++] in myObj); document.write(myKeys); For In Over Arrays for in statement can also loop over the properties of an Array: const numbers = [45, 4, 9, 16, 25]; let txt = ""; for (let x in numbers) { txt += numbers[x]; } Do not use for in over an Array if the index order is important. The index order is implementation-dependent, and array values may not be accessed in the order you expect. It is better to use a for loop, a for of loop, or Array.forEach() when the order is important. Array.forEach() The forEach() method calls a function (a callback function) once for each array element. const numbers = [45, 4, 9, 16, 25]; let txt = ""; numbers.forEach(myFunction); function myFunction(value, index, array) { txt += value; } Note that the function takes 3 arguments: Example const numbers = [45, 4, 9, 16, 25]; let txt = ""; numbers.forEach(myFunction); function myFunction(value) { txt += value; }

    For…of Loop

    The for...of statement creates a loop iterating over iterable objects (including Array, Map, Set, Strings, NodeLists, Arguments object and so on) for (variable of object) { statement } const cars = ["BMW", "Volvo", "Mini"]; // this time use array text = ""; for (x of cars) { text += x + " "; } $("#log").append("
    ",text) To exit loop before the end condition evaluates to false. Use a break statement Looping over an Array Example const cars = ["BMW", "Volvo", "Mini"]; let text = ""; for (let x of cars) { text += x; } Looping over a String Example let language = "JavaScript"; text = ""; for (let x of language) { text += x; }

    Map

    var m = new Map(); m.set(1, "black"); m.set(2, "red"); for (var n of m) { console.log(n); } // Output: // 1,black // 2,red

    Set

    var s = new Set(); s.add(1); s.add("red"); for (var n of s) { console.log(n); } // Output: // 1 // red

    Arguments object

    // your browser must support for..of loop // and let-scoped variables in for loops function displayArgumentsObject() { for (let n of arguments) { console.log(n); } } displayArgumentsObject(1, 'red'); // Output: // 1 // red

    Break Statement Example

    The break statement terminates the current loop, switch or label statement and transfers program control to the statement following the terminated statement. If the break statement is used in a labeled statement, the syntax is as follows: break labelName; Examples function testBreak(x) { var i = 0; while (i < 6) { if (i == 3) { break; } i += 1; } return i * x; }

    While Loop Example

    The while loop starts by evaluating the condition. If the condition is true, the statement(s) is/are executed. If the condition is false, the statement(s) is/are not executed. After that, while loop ends. Here is the syntax for the while loop: Syntax: while (condition) { statement(s); } statement(s): A statement that is executed as long as the condition evaluates to true. condition: Here, the condition is a Boolean expression which is evaluated before each pass through the loop. If this condition evaluates to true, statement(s) is/are executed. When the condition evaluates to false, execution continues with the statement after the while loop. Example: var i = 1; while (i < 10) { console.log(i); i++; // i=i+1 same thing } Output: 1 2 3 4 5 6 7 8 9

    Forms & Functions

    create a form <form name="formname"> </form> Place a text box <input type="text" name="boxname"> window.document.formname.first_text.value='Hi there'; This tells the browser to put 'Hi there!' into the value of the item called 'first_text' in the form called 'formname'.

    To make sure an input field has a value before submit

    using the required attribute in HTML5: <input id="m" autocomplete="off" required/> but you can just turn it of in browser console recommend: if (document.getElementById("m").value == '') { //code here... }

    Accessing Values

    <form name="feedback" action="script.cgi" method="post" onSubmit="return checkform()"> <input type="text" name="name"> <input type="text" name="email"> <textarea name="comments"></textarea> </form> To get the value from all types of form elements.

    Text Boxes, <textarea>s and hiddens

    document.feedback.field.value You'll usually be checking if this value is empty, i.e. if (document.feedback.field.value == '') {return false; }

    Select Boxes

    Each option in a drop-down box is indexed in the array options[], starting as always with 0. You then get the value of the element at this index. It's like this: document.feedback.field.options [document.feedback.field.selectedIndex].value You can also change the selected index through JavaScript. To set it to the first option, execute this: document.feedback.field.selectedIndex = 0;

    Check Boxes

    Checkboxes behave differently to other elements — their value is always on. Instead, you have to check if their Boolean checked value is true or, in this case, false. if (!document.feedback.field.checked) {// box is not checkedreturn false; } Naturally, to check a box, do this document.feedback.field.checked = true;

    Radio Buttons

    Annoyingly, there is no simple way to check which radio button out of a group is selected — you have to check through each element, linked with Boolean AND operators . Usually you'll just want to check if none of them have been selected, as in this example: if (!document.feedback.field[0].checked && !document.feedback.field[1].checked && !document.feedback.field[2].checked) {// no radio button is selectedreturn false; }

    Capture a form submit in JavaScript

    Using onsubmit:

    <form action="action.php" onsubmit="myFunction()"> Enter name: <input type="text" name="fname"> <input type="submit" value="Submit"> </form> function myFunction() { alert("The form was submitted"); }

    Using JQuery on button:

    <form id="my-form"> <input type="text" name="in" value="some data" /> <button type="submit">Go</button> </form> $('button').click(function() { //do something; });

    JavaScript Form action using return

    function validateForm() { var x = document.forms["myForm"]["fname"].value; if (x == "") { alert("No data"); return false;} } <form name="myForm" action="action.php" onsubmit="return validateForm()" method="post"> Name: <input type="text" name="fname"> <input type="submit" value="Submit"> </form> ===========================

    Checkboxes

    if(window.document.example1.my_checkbox.checked=true) { alert('The box is checked!') } else { window.document.example1.my_checkbox.checked=true; alert('The box was not checked so I have checked it!'); } // show number checked alert($(":checkbox:checked").length); ===========================

    The JavaScript Switch Statement

    switch(expression) { case n: code block break; case n: code block break; default: code block } ===========================

    Common Code Blocks

    switch (new Date().getDay()) { case 4: case 5: text = "Soon it is Weekend"; break; case 0: case 6: text = "It is Weekend"; break; default: text = "Looking forward to the Weekend"; } ===========================

    Break and Continue

    for (i = 0; i < 10; i++) { if (i === 3) { break; } text += "The number is " + i + "<br>"; } for (i = 0; i < 10; i++) { if (i === 3) { continue; } text += "The number is " + i + "<br>"; }

    Labels

    label: statements break labelname; continue labelname; var cars = ["BMW", "Volvo", "Saab", "Ford"]; list: { text += cars[0] + "<br>"; text += cars[1] + "<br>"; text += cars[2] + "<br>"; break list; text += cars[3] + "<br>"; text += cars[4] + "<br>"; text += cars[5] + "<br>"; } ===========================

    sCt(stkcode)

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script> function sCt(stkcode) { imgHead = "<img src='http://charts.aastocks.com/servlet/Charts?fontsize=12&15MinDelay=F&lang=1&titlestyle=1&vol=1&Indicator=9&indpara1=20&indpara2=2&indpara3=0&indpara4=0&indpara5=0&subChart1=3&ref1para1=5&ref1para2=10&ref1para3=3&subChart2=3&ref2para1=12&ref2para2=26&ref2para3=9&subChart3=12&ref3para1=0&ref3para2=0&ref3para3=0&scheme=3&com=100&chartwidth=1150&chartheight=690&stockid="; imgPCode= "&period="; imgTail="&type=1&logoStyle=1'><br><br>"; intv = [7, 4, 3, 11]; var imgWindow = window.open(""); theListDom ='<meta http-equiv="refresh" content="60"><style type="text/css">body { margin-top: 2%; margin-bottom: 2%; margin-right: 3%; margin-left: 3%; background-color: #000000;}</style><body><br>' for( var imgPeriod = 0; imgPeriod < intv.length; imgPeriod++){ theListDom = theListDom + imgHead + stkcode + imgPCode + intv[imgPeriod] + imgTail; }; imgWindow.document.write(theListDom); } </script> ===========================

    History go() Method()

    <button onclick="goBack()">Go Back 2 Pages function goBack() { window.history.go(-2); } Go forward one page (This example will not work if the next page does not exist in the history list): window.history.go(1);

    history.back()

    <script> $(document).ready(function(){ $('.keys').click(function(){ parent.history.back(); return false; }); }); </script> ===========================

    function chkKey()

    Note: the id tag cannot be located inside b, should be p or div function chkKey() { var testkey = getChar(event); if(testkey == '9'){ sCt(992); } if(testkey == 'h'){ sCt(110000); } if(testkey == 'a'){ sCt("000001.sh"); } if(testkey == 'f'){ window.location = '#stkcodeid'; $('#stkcode').value =""; } if(testkey == 'A'){ window.location = '#Astock'; } } ===========================

    Go Bottom

    <b class="left" onclick="window.scrollTo(0,document.body.scrollHeight);">Go Bottom</b> | <div id ="codelist"></div> Scroll to Top: window.scrollTo(0,0); ===========================

    HTML DOM scrollTop Property

    The scrollTop property sets or returns the number of pixels an element's content is scrolled vertically. Example Get the number of pixels the content of a <div> element is scrolled horizontally and vertically: var elmnt = document.getElementById("myDIV"); var x = elmnt.scrollLeft; var y = elmnt.scrollTop; Note: this is only a property, not a method, it won't move, and the return value is just one interger, showing the scrolled distance, and if the previous action did not scrolled, the distance is zero.

    HTML DOM scrollIntoView Method

    Example Scroll the element with id="content" into the visible area of the browser window: var elmnt = document.getElementById("content"); elmnt.scrollIntoView(); ===========================

    auto scroll page

    $("html, body").animate({ scrollTop: $(document).height() }, 3000000); divtoc = document.getElementById("stkChart"); $('body,html').animate({scrollTop:(divtoc.clientHeight + divtoc.offsetTop-1480)}, 1); $( "#book" ).animate({ width: [ "toggle", "swing" ], height: [ "toggle", "swing" ], opacity: "toggle" }, 5000, "linear", function() { $( this ).after( "Animation complete." ); }); ==========

    The animate() method

    (selector).animate({styles},speed,easing,callback) The animate() method performs a custom animation of a set of CSS properties. $("#box").animate({height: "300px"}); $( "p" ).animate({ height: 200, width: 400, opacity: 0.5 }, 1000, "linear", function() { alert( "all done" ); }); Alternate Syntax (selector).animate({styles},{options}) ======== Parameter Description styles Required. Specifies one or more CSS properties/values to animate. Note: The property names must be camel-cased when used with the animate() method: You will need to write paddingLeft instead of padding-left, marginRight instead of margin-right, and so on. Most properties that are non-numeric cannot be animated using basic jQuery functionality For example, width, height, or left can be animated but background-color cannot be, unless the jQuery.Color plugin is used. Property values are treated as a number of pixels unless otherwise specified. The units em and % can be specified where applicable. Only numeric values can be animated (like "margin:30px"). String values cannot be animated (like "background-color:red"), except for the strings "show", "hide" and "toggle". These values allow hiding and showing the animated element. ======== Properties that can be animated: backgroundPositionX, backgroundPositionY, borderWidth, borderBottomWidth, borderLeftWidth, borderRightWidth, borderTopWidth, borderSpacing, margin, marginBottom, marginLeft, marginRight, marginTop, opacity, outlineWidth, padding, paddingBottom, paddingLeft, paddingRight, paddingTop, height, width, maxHeight, maxWidth, minHeight, minWidth, fontSize, bottom, left, right, top, letterSpacing, wordSpacing, lineHeight, textIndent ======== speed Optional. Specifies the speed of the animation. Default value is 400 milliseconds Possible values: milliseconds (like 100, 1000, 5000, etc), "slow", "fast" ======== easing Optional. Specifies the speed of the element in different points of the animation. Default value is "swing". Possible values: "swing" - moves slower at the beginning/end, but faster in the middle "linear" - moves in a constant speed Tip: More easing functions are available in external plugins. ======== callback Optional. A function to be executed after the animation completes. ======== Alternate Syntax options Optional. Specifies additional options for the animation. Possible values: duration the speed of the animation easing the easing function to use complete a function to be executed after the animation completes step a function to be executed for each step in the animation progress a function to be executed after each step in the animation queue a Boolean value specifying whether or not to place the animation in the effects queue specialEasing a map of one or more CSS properties from the styles parameter, and their corresponding easing functions start a function to be executed when the animation begins done a function to be executed when the animation ends fail a function to be executed if the animation fails to complete always a function to be executed if the animation stops without completing ==========

    window.scrollBy(0,1);

    scrolldelay = setTimeout(pageScroll,5); ==========

    Select file

    <html> <head> <script type="text/javascript"> function alertFilename() { var thefile = document.getElementById('thefile'); alert(thefile.value); } </script> </head> <body> <form> <input type="file" id="thefile" onchange="alertFilename()" /> <input type="button" onclick="alertFilename()" value="alert" /> </form> </body> </html> ===========================

    input

    <input type="submit" name="Button1" value="查詢過往資料(SEARCH)" onclick="if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(); " language="javascript" id="Button1" class="b"> ===========================

    JSON

    var json = '{"result":true,"count":1}', obj = JSON.parse(theUrl); JSON.parse(theUrl); or jQuery.getJSON(): data = '[{"name" : "Ashwin", "age" : "20"},{"name" : "Abhinandan", "age" : "20"}]'; Mention the path of the json file in the script source along with the javascript file. <script type="text/javascript" src="data.json"></script> <script type="text/javascript" src="javascrip.js"></script> Get the Object from the json file var mydata = JSON.parse(data); alert(mydata[0].name); alert(mydata[0].age); alert(mydata[1].name); alert(mydata[1].age); to store data in jquery, data = [] and update later ===========================

    Detecting double-press of a key

    <head> <script type="text/javascript"> function checkspace(event){if (window.event.keyCode == 32) alert('Stop that!');} </script> </head> <body> <BODY onKeydown="checkspace()"> Replace alert with whatever it is you want it to do. Then you could do a counter function that increments by 100 every 100ms, and do an if var keypresses = 0; var counter = 0; startcouting(); if(event.keyCode == 32){ keypresses += 1; } if(keypresses == 2 && counter <= 500){ do something; reset the counter; } ===========================

    Detecting key press

    https://stackoverflow.com/questions/19502155/detecting-multiple-key-press-in-javascript Detecting multiple key press in javascript https://stackoverflow.com/questions/5203407/javascript-multiple-keys-pressed-at-once JavaScript multiple keys pressed at once The simplest way to find out whether the ctrl is pressed, is to test the event object for the ctrlKey property: $(document).keypress(function(e){ console.log(e.which, e.ctrlKey); }); ===========================

    button onclick open programs

    <button onclick="window.open('file:///C:/Windows/notepad.exe')"> Launch notepad </button> ===========================

    wechatQrcode

    <script type="text/javascript" src="js/jquery-1.11.3.min.js" charset="utf-8"></script> <script type="text/javascript" src="js/jquery-migrate-1.2.1.min.js" charset="utf-8"></script> <script src="js/jquery.share.min.js?ver=1.1" type="text/javascript"></script> <script type="text/javascript"> $(function(){ var $config = { url: 'http://sign.hknt.hk/', sites: ['facebook', 'wechat', 'twitter'], wechatQrcodeTitle: '微信掃一掃', wechatQrcodeHelper: '<p>將活動地址分享到朋友圈</p>' }; if (/MicroMessenger/i.test(navigator.userAgent)) { $config.wechatQrcodeTitle = 'QR Code'; $config.wechatQrcodeHelper = '<p>長按 QR Code 識別</p>'; } $('#social-share').share($config); var mask = $('#share-mask'); $('#social-share').children('a').on('click',function(e){ if(/MicroMessenger/i.test(navigator.userAgent) && (this.className.indexOf('icon-whatsapp') != -1)){ e.preventDefault(); mask.show().on('click',function mehide(){ $(this).hide().off('click',mehide); }); } }); var titlediv = $('#title-div'), chart = $('.chart-num').children('span'); $.ajax({ url: 'get_data.php', type: 'get', dataType: 'json', success: function(data){ titlediv.children('span').each(function(i){ switch(i){ case 0: this.innerText = data['end_date'][1];break; case 1: this.innerText = data['end_date'][2];break; case 2: this.innerText = data['end_time'][0];break; case 3: this.innerText = data['total'];break; } }); chart.each(function(i){ switch(i){ case 0: this.innerText = data['sector_1']; break; case 1: this.innerText = data['sector_2']; break; case 2: this.innerText = data['sector_0']; break; } }); }, error: function(err){ console.log('err',err); } }); }); </script> ===========================

    chkKey()

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script> <script> function chkKey() { var testkey = getChar(event); if(testkey == 'n'){ window.location = '#xinwen'; } } function getChar(event) { if(testkey == 'y'){ window.open("http://www.youtube.com"); } if (event.which!=0 && event.charCode!=0) { return String.fromCharCode(event.which) // the rest } else { return null // special key } } </script> ===========================

    sCt(stkcode)

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <body onkeypress="chkKey()"> <script> function sCt(stkcode) { imgHead = "<img src='http://charts.aastocks.com/servlet/Charts?fontsize=12&15MinDelay=F&lang=1&titlestyle=1&vol=1&Indicator=9&indpara1=20&indpara2=2&indpara3=0&indpara4=0&indpara5=0&subChart1=3&ref1para1=5&ref1para2=10&ref1para3=3&subChart2=3&ref2para1=12&ref2para2=26&ref2para3=9&subChart3=12&ref3para1=0&ref3para2=0&ref3para3=0&scheme=3&com=100&chartwidth=1150&chartheight=690&stockid="; imgPCode= "&period="; imgTail="&type=1&logoStyle=1'><br><br>"; intv = [4, 3, 2, 1, 5012, 5007, 5000, 7, 11]; var imgWindow = window.open(""); imgAdr ='<meta http-equiv="refresh" content="60"><br>' for( var imgPeriod = 0; imgPeriod < intv.length; imgPeriod++){ imgAdr = imgAdr + imgHead + stkcode + imgPCode + intv[imgPeriod] + imgTail; }; imgWindow.document.write(imgAdr); } </script> <script> $(document).ready(function(){ $('.keys').click(function(){ parent.history.back(); return false; }); }); function chkKey() { var testkey = getChar(event); if(testkey == 'f'){ window.location = '#stkcodeid'; $('#stkcode').value =""; } if(testkey == 'A'){ window.location = '#Astock'; } } function getChar(event) { if (event.which!=0 && event.charCode!=0) { return String.fromCharCode(event.which) // the rest } else { return null // special key } } function openHtml(){ console.log( "keypress: " + $(this).value ); }; </script> <b class="left" onclick="window.scrollTo(0,document.body.scrollHeight);">Go Bottom</b> | <b onclick=sCt("02823")>02823</b> | ===========================

    get radio elements value and compare

    var submitAnswer = function() { var radios = document.getElementsByName('choice'); var val= ""; for (var i = 0, length = radios.length; i < length; i++) { if (radios[i].checked) { val = radios[i].value; break; } } if (val == "" ) { alert('please select choice answer'); } else if ( val == "Scripting" ) { alert('Answer is correct !'); } else { alert('Answer is wrong'); } }; <h1>JavaScript is ______ Language.</h1><br> <form > <input type="radio" name="choice" value="Scripting"> Scripting <input type="radio" name="choice" value="Programming"> Programming <input type="radio" name="choice" value="Application"> Application <input type="radio" name="choice" value="None of These"> None of These </form> <button onclick="submitAnswer()">Submit Answer</button> ===========================

    access object

    const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] }; console.log(data.items); console.log(data.items[0]); console.log(data.items[1]); console.log(data.items[0].name); console.log(data.items[0].id); ===========================

    This is the create TOC improved version

    $(function() { var toc = $('#toc'); $('h2').each(function(i) { var topic = $(this), topicNum = i + 1; toc.append('<a href="#topic-' + topicNum + '" target="_self">' + topic.text() + '</a><br>'); topic.attr('id', 'topic-' + topicNum); }); }); ===========================

    jQuery Manipulating CSS

    addClass() - Adds one or more classes to the selected elements removeClass() - Removes one or more classes from the selected elements toggleClass() - Toggles between adding/removing classes css() - Sets or returns the style attribute $("button").click(function(){ $("h1, h2, p").addClass("blue"); $("div").addClass("important"); });

    jQuery addClass() Method

    Add a class name to the first p element: $("button").click(function(){ $("p:first").addClass("intro"); }); Tip: To add more than one class, separate the class names with spaces. $(selector).addClass(classname,function(index,currentclass))

    changesize(newFontSize)

    function changesize(newFontSize) { var currentFontSize = getCookie("fontsize"); if (newFontSize != currentFontSize) { $("html").addClass(newFontSize); $("#fontsize" + newFontSize).addClass("selected"); if (currentFontSize != "") { $("html").removeClass(currentFontSize); $("#fontsize" + currentFontSize).removeClass("selected"); } setCookie("fontsize", newFontSize); } } ===========================

    Cookies

    Cookies are saved in name-value pairs like: username = John Doe Create a Cookie with JavaScript document.cookie = "username=John Doe"; add an expiry date. By default, the cookie is deleted when the browser is closed. document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC"; Tell the browser what path the cookie belongs to with a path parameter. By default, the cookie belongs to the current page. document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/"; Read a Cookie with JavaScript var x = document.cookie; will return all cookies in one string much like: cookie1=value; cookie2=value; cookie3=value; Delete a Cookie with JavaScript Just set the expires parameter to a passed date document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; The Cookie String The document.cookie property looks like a normal text string. But it is not. Even if you write a whole cookie string to document.cookie, when you read it out again, you can only see the name-value pair of it. If you set a new cookie, older cookies are not overwritten. The new cookie is added to document.cookie, so if you read document.cookie again you will get something like: cookie1 = value; cookie2 = value;

    functions to handle Cookies



    Set a Cookie
    Get a Cookie
    Check a Cookie

    Set a Cookie

    First, we create a function that stores the name of the visitor in a cookie variable: Example function setCookie(cname, cvalue, exdays) { var d = new Date(); d.setTime(d.getTime() + (exdays*24*60*60*1000)); var expires = "expires="+ d.toUTCString(); document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; }

    Get a Cookie

    Then, we create a function that returns the value of a specified cookie: Example function getCookie(cname) { var name = cname + "="; var decodedCookie = decodeURIComponent(document.cookie); var ca = decodedCookie.split(';'); for(var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') { c = c.substring(1); } if (c.indexOf(name) == 0){ return c.substring(name.length, c.length);} } return ""; }

    Check a Cookie

    checks if a cookie is set. If the cookie is set it will display a greeting. If the cookie is not set, it will display a prompt box, asking for the name of the user, and stores the username cookie for 365 days, by calling the setCookie function: Example function checkCookie() { var username = getCookie("username"); if (username != "") { alert("Welcome again " + username); } else { username = prompt("Please enter your name:", ""); if (username != "" && username != null) { setCookie("username", username, 365); } } }

    javascript:void(0) 含义

    javascript:void(0) 中最关键的是 void 关键字, void 是 JavaScript 中非常重要的关键字,该操作符指定要计算一个表达式但是不返回值。 实例 <a href="javascript:void(0)">单击此处什么也不会发生</a> href="#" 与 href="javascript:void(0)" 的区别 # 包含了一个位置信息,默认的锚是#top 也就是网页的上端。 而javascript:void(0), 仅仅表示一个死链接。 在页面很长的时候会使用 # 来定位页面的具体位置,格式为: # + id。 如果你要定义一个死链接请使用 javascript:void(0) 。 实例 <a href="javascript:void(0);">点我没有反应的!</a> <a href="#pos">点我定位到指定位置!</a> <br> ... <br> <p id="pos">尾部定位点</p> ===========================

    href="#"

    A hash - # within a hyperlink specifies an html element id to which the window should be scrolled. Scroll to Top: href="#" doesn't specify an id name, but does have a corresponding location - the top of the page. Clicking an anchor with href="#" will move the scroll position to the top. <a href="#" onclick="fn()">click here</a> you will jump to the top and the URL will have the anchor # as well, to avoid this we simply return false; or use javascript:void(0); regarding your examples <a onclick="fn()">Does not appear as a link, because there's no href</a> just do a {text-decoration:underline;} and you will have "link a-like" <a href="javascript:void(0)" onclick="fn()">fn is called</a> <a href="javascript:" onclick="fn()">fn is called too!</a> it's ok, but in your function at the end, just return false; to prevent the default behavior, you don't need to do anything more. Link to an email address: <a href="mailto:someone@example.com">Send email</a> Link to a phone number: <a href="tel:+4733378901">+47 333 78 901</a> Link to another section on the same page: <a href="#section2">Go to Section 2</a> Link to a JavaScript: <a href="javascript:alert('Hello World!');">Execute JavaScript</a> ===========================

    Jquery If This Contains


    Jquery If This Contains find element where child items h2 text has a specific value selecting children sample
    get the children of the this selector var toc = $('#toc>ul'); toc.append($(".parent").find("p:contains('Statistics')").parent().text()) by javascript: var myDomElement = document.getElementById( "foo" ); // A plain DOM element. $( myDomElement ).find( "a" ); // Finds =========================== Loops: while and for let i = 0; while (i < 3) { // shows 0, then 1, then 2 alert( i ); i++; } the shorter way to write while (i != 0) could be while (i): let i = 3; while (i) { alert( i ); i--; } Brackets are not required for a single-line body If the loop body has a single statement, we can omit the brackets {…}: let i = 3; while (i) alert(i--); The “do…while” loop The condition check can be moved below the loop body using the do..while syntax: do { // loop body } while (condition); The loop will first execute the body, then check the condition and, while it’s truthy, execute it again and again. For example: let i = 0; do { alert( i ); i++; } while (i < 3); This form of syntax is rarely used except when you want the body of the loop to execute at least once regardless of the condition being truthy. Usually, the other form is preferred: while(…) {…}. The “for” loop The for loop is the most often used one. It looks like this: for (begin; condition; step) { // ... loop body ... } Let’s learn the meaning of these parts by example. The loop below runs alert(i) for i from 0 up to (but not including) 3: for (let i = 0; i < 3; i++) { // shows 0, then 1, then 2 alert(i); } Let’s examine the for statement part by part: part begin i = 0 Executes once upon entering the loop. condition i < 3 Checked before every loop iteration, if fails the loop stops. step i++ Executes after the body on each iteration, but before the condition check. body alert(i) Runs again and again while the condition is truthy The general loop algorithm works like this: Run begin → (if condition → run body and run step) → (if condition → run body and run step) → (if condition → run body and run step) → ... If you are new to loops, then maybe it would help if you go back to the example and reproduce how it runs step-by-step on a piece of paper. Here’s what exactly happens in our case: // for (let i = 0; i < 3; i++) alert(i) // run begin let i = 0 // if condition → run body and run step if (i < 3) { alert(i); i++ } // if condition → run body and run step if (i < 3) { alert(i); i++ } // if condition → run body and run step if (i < 3) { alert(i); i++ } // ...finish, because now i == 3 Inline variable declaration Here the “counter” variable i is declared right in the loop. That’s called an “inline” variable declaration. Such variables are visible only inside the loop. for (let i = 0; i < 3; i++) { alert(i); // 0, 1, 2 } alert(i); // error, no such variable Instead of defining a variable, we can use an existing one: let i = 0; for (i = 0; i < 3; i++) { // use an existing variable alert(i); // 0, 1, 2 } alert(i); // 3, visible, because declared outside of the loop Skipping parts Any part of for can be skipped. For example, we can omit begin if we don’t need to do anything at the loop start. Like here: let i = 0; // we have i already declared and assigned for (; i < 3; i++) { // no need for "begin" alert( i ); // 0, 1, 2 } We can also remove the step part: let i = 0; for (; i < 3;) { alert( i++ ); } The loop became identical to while (i < 3). We can actually remove everything, thus creating an infinite loop: for (;;) { // repeats without limits } Please note that the two for semicolons ; must be present, otherwise it would be a syntax error. Breaking the loop Normally the loop exits when the condition becomes falsy. But we can force the exit at any moment. There’s a special break directive for that. For example, the loop below asks the user for a series of numbers, but “breaks” when no number is entered: let sum = 0; while (true) { let value = +prompt("Enter a number", ''); if (!value) break; // (*) sum += value; } alert( 'Sum: ' + sum ); The break directive is activated in the line (*) if the user enters an empty line or cancels the input. It stops the loop immediately, passing the control to the first line after the loop. Namely, alert. The combination “infinite loop + break as needed” is great for situations when the condition must be checked not in the beginning/end of the loop, but in the middle, or even in several places of the body. Continue to the next iteration The continue directive is a “lighter version” of break. It doesn’t stop the whole loop. Instead it stops the current iteration and forces the loop to start a new one (if the condition allows). We can use it if we’re done on the current iteration and would like to move on to the next. The loop below uses continue to output only odd values: for (let i = 0; i < 10; i++) { // if true, skip the remaining part of the body if (i % 2 == 0) continue; alert(i); // 1, then 3, 5, 7, 9 } For even values of i the continue directive stops body execution, passing the control to the next iteration of for (with the next number). So the alert is only called for odd values. The directive continue helps to decrease nesting level A loop that shows odd values could look like this: for (let i = 0; i < 10; i++) { if (i % 2) { alert( i ); } } From a technical point of view it’s identical to the example above. Surely, we can just wrap the code in the if block instead of continue. But as a side-effect we got one more figure brackets nesting level. If the code inside if is longer than a few lines, that may decrease the overall readability. No break/continue to the right side of ‘?’ Please note that syntax constructs that are not expressions cannot be used in '?'. In particular, directives break/continue are disallowed there. For example, if we take this code: if (i > 5) { alert(i); } else { continue; } …And rewrite it using a question mark: (i > 5) ? alert(i) : continue; // continue not allowed here …Then it stops working. The code like this will give a syntax error: That’s just another reason not to use a question mark operator '?' instead of if. Labels for break/continue Sometimes we need to break out from multiple nested loops at once. For example, in the code below we loop over i and j prompting for coordinates (i, j) from (0,0) to (3,3): for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { let input = prompt(`Value at coords (${i},${j})`, ''); // what if I want to exit from here to Done (below)? } } alert('Done!'); We need a way to stop the process if the user cancels the input. The ordinary break after input would only break the inner loop. That’s not sufficient. Labels come to the rescue. A label is an identifier with a colon before a loop: labelName: for (...) { ... } The break <labelName> statement in the loop breaks out to the label. Like here: outer: for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { let input = prompt(`Value at coords (${i},${j})`, ''); // if an empty string or canceled, then break out of both loops if (!input) break outer; // (*) // do something with the value... } } alert('Done!'); In the code above break outer looks upwards for the label named outer and breaks out of that loop. So the control goes straight from (*) to alert('Done!'). We can also move the label onto a separate line: outer: for (let i = 0; i < 3; i++) { ... } The continue directive can also be used with a label. In this case the execution jumps to the next iteration of the labeled loop. Labels are not a “goto” Labels do not allow us to jump into an arbitrary place of code. For example, it is impossible to do this: break label; // jumps to label? No. label: for (...) The call to a break/continue is only possible from inside the loop, and the label must be somewhere upwards from the directive. Summary We covered 3 types of loops: while – The condition is checked before each iteration. do..while – The condition is checked after each iteration. for (;;) – The condition is checked before each iteration, additional settings available. To make an “infinite” loop, usually the while(true) construct is used. Such a loop, just like any other, can be stopped with the break directive. If we don’t want to do anything on the current iteration and would like to forward to the next one, the continue directive does it. Break/continue support labels before the loop. A label is the only way for break/continue to escape the nesting and go to the outer loop. Tasks Last loop value importance: 3 What is the last value alerted by this code? Why? let i = 3; while (i) { alert( i-- ); } solution Which values shows the while? importance: 4 For every loop, write down which values it shows, in your opinion. And then compare with the answer. Both loops alert same values or not? The prefix form ++i: let i = 0; while (++i < 5) alert( i ); The postfix form i++ let i = 0; while (i++ < 5) alert( i ); solution Which values get shown by the "for" loop? importance: 4 For each loop write down which values it is going to show. Then compare with the answer. Both loops alert same values or not? The postfix form: for (let i = 0; i < 5; i++) alert( i ); The prefix form: for (let i = 0; i < 5; ++i) alert( i ); solution Output even numbers in the loop importance: 5 Use the for loop to output even numbers from 2 to 10. Run the demo solution Replace "for" with "while" importance: 5 Rewrite the code changing the for loop to while without altering its behavior (the output should stay same). for (let i = 0; i < 3; i++) { alert( `number ${i}!` ); } solution Repeat until the input is correct importance: 5 Write a loop which prompts for a number greater than 100. If the visitor enters another number – ask him to input again. The loop must ask for a number until either the visitor enters a number greater than 100 or cancels the input/enters an empty line. Here we can assume that the visitor only inputs numbers. There’s no need to implement a special handling for a non-numeric input in this task. Run the demo solution Output prime numbers importance: 3 An integer number greater than 1 is called a prime if it cannot be divided without a remainder by anything except 1 and itself. In other words, n > 1 is a prime if it can’t be evenly divided by anything except 1 and n. For example, 5 is a prime, because it cannot be divided without a remainder by 2, 3 and 4. Write the code which outputs prime numbers in the interval from 2 to n. For n = 10 the result will be 2,3,5,7. P.S. The code should work for any n, not be hard-tuned for any fixed value. ===========================

    android javascript tts

    var msg = new SpeechSynthesisUtterance('Hello World');
    window.speechSynthesis.speak(msg);
    ===========================

    Google Maps in HTML

    Google Maps in HTML
    <html> <body> <div id="googleMap" style="width:100%;height:400px;"></div> <script> function myMap() { var mapProp= { center:new google.maps.LatLng(51.508742,-0.120850), zoom:5,}; var map=new google.maps.Map(document.getElementById("googleMap"),mapProp);} </script> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBu-916DdpKAjTmJNIgngS6HL_kDIKU0aU&callback=myMap"> </script> <!-- To use this code on your website, get a free API key from Google. Read more at: https://www.w3schools.com/graphics/google_maps_basic.asp --> </body> </html>

    examples

    JavaScript can change HTML content. <button type="button" onclick='document.getElementById("demo").innerHTML = "Hello JavaScript!"'>Click Me!</button> JavaScript can change HTML attributes. <button onclick="document.getElementById('myImage').src='pic_bulbon.gif'">Turn on the light</button> <img id="myImage" src="pic_bulboff.gif" style="width:100px"> <button onclick="document.getElementById('myImage').src='pic_bulboff.gif'">Turn off the light</button> JavaScript can change the style of an HTML element. <button type="button" onclick="document.getElementById('demo').style.fontSize='35px'">Click Me!</button> JavaScript can hide HTML elements. <button type="button" onclick="document.getElementById('demo').style.display='none'">Click Me!</button> JavaScript can show hidden HTML elements. <button type="button" onclick="document.getElementById('demo').style.display='block'">Click Me!</button> Writing into an window alert box window.alert(5 + 6); Writing into the HTML output document.write(5 + 6); Writing into an HTML element document.getElementById("demo").innerHTML = 5 + 6; Writing into the browser console console.log(5 + 6); JavaScript in <head> <script> document.getElementById("demo").innerHTML = "Paragraph changed."; </script> JavaScript in <body> <script> document.getElementById("demo").innerHTML = "Paragraph changed."; </script> JavaScript in an external file <script src="myScript.js"></script> External JavaScript Advantages: separates HTML and code, makes HTML and JavaScript easier to read and maintain, Cached JavaScript files can speed up page loads. JavaScript Statements A JavaScript program is a list of statements to be executed by a computer. var x, y, z; // Declare 3 variables x = 5; // Assign the value 5 to x y = 6; // Assign the value 6 to y z = x + y; // Assign the sum of x and y to z document.getElementById("demo").innerHTML = "The value of z is " + z + "."; JavaScript Numbers document.getElementById("demo").innerHTML = 10.50; JavaScript strings Strings can be written with double or single quotes. document.getElementById("demo").innerHTML = 'John Doe'; JavaScript expressions Expressions compute to values. document.getElementById("demo").innerHTML = 5 * 10; JavaScript keywords The var Keyword Creates Variables var x, y; JavaScript variables var x; x = 6; JavaScript assignment the = operator is used to assign values to variables. x = 5; JavaScript operators use arithmetic operators to compute values (just like algebra). document.getElementById("demo").innerHTML = (5 + 6) * 10; JavaScript comments JavaScript Comments are NOT Executed // x = 6; I will not be executed JavaScript is case sensitive lastName = "Doe"; lastname = "Peterson"; JavaScript statements are commands to the browser In HTML, JavaScript statements are executed by the browser. JavaScript code is a sequence of statements A JavaScript program is a list of statements to be executed by a computer. JavaScript statements are separated with semicolon JavaScript statements are separated by semicolons. Multiple statements on one line is allowed. a = 1; b = 2; c = a + b; JavaScript statements can be grouped together in code blocks JavaScript code blocks are written between { and } function myFunction() { document.getElementById("demo1").innerHTML = "Hello Dolly!"; document.getElementById("demo2").innerHTML = "How are you?"; } You can break a code line after an operator or a comma. The best place to break a code line is after an operator or a comma. document.getElementById("demo").innerHTML = "Hello Dolly!"; Single line comments // Change heading: Single line comments at the end of a line var x = 5; // Declare x, give it the value of 5 Multiple lines comments /* The code below will change the heading with id = "myH" and the paragraph with id = "myp" in my web page: */ Single line comment to prevent execution //document.getElementById("myH").innerHTML = "My First Page"; Multiple lines comment to prevent execution /* document.getElementById("myH").innerHTML = "Welcome to my Homepage"; document.getElementById("myP").innerHTML = "This is my first paragraph."; */ JavaScript variables as algebra var total = price1 + price2; JavaScript numbers and strings Strings are written with quotes. Numbers are written without quotes. Declaring many variables in one statement You can declare many variables in one statement. var person = "John Doe", carName = "Volvo", price = 200; Declaring many variables multiline var person = "John Doe", carName = "Volvo", price = 200; A variable without a value returns the value undefined var carName; Re-declaring a variable will not destroy the value var carName = "Volvo"; var carName; Adding JavaScript numbers var x = 5 + 2 + 3; Adding JavaScript strings var x = "John" + " " + "Doe"; Adding strings and numbers gives string x = "5" + 2 + 3; The modulus (%) operator var z = x % y; The increment (++) operator increment The decrement (--) operator decrement The = assignment operator var x = 10; The += assignment operator var x = 10; x += 5; // = 15 The -= assignment operator var x = 10; x -= 5; // = 5 The *= assignment operator var x = 10; x *= 5; // = 50 The /= assignment operator var x = 10; x /= 5; // = 2 The %= assignment operator var x = 10; x %= 5; // = 0 Adding two strings together using the concatenating (+) operator var txt1 = "What a very"; var txt2 = "nice day"; document.getElementById("demo").innerHTML = txt1 + txt2; Adding two strings together using using the += operator txt1 = "What a very "; txt1 += "nice day"; document.getElementById("demo").innerHTML = txt1; Adding strings and numbers var x = 5 + 5; var y = "5" + 5; var z = "Hello" + 5; document.getElementById("demo").innerHTML = x + "<br>" + y + "<br>" + z; Declare (create) strings var answer1 = "It's alright"; var answer2 = "He is called 'Johnny'"; var answer3 = 'He is called "Johnny"'; document.getElementById("demo").innerHTML = answer1 + "<br>" + answer2 + "<br>" + answer3; Declare (create) numbers var x1 = 34.00; var x2 = 34; var x3 = 3.14; document.getElementById("demo").innerHTML = x1 + "<br>" + x2 + "<br>" + x3; Declare (create) an array var cars = ["Saab","Volvo","BMW"]; document.getElementById("demo").innerHTML = cars[0]; Declare (create) an object var person = { firstName : "John", lastName : "Doe", age : 50, eyeColor : "blue" }; document.getElementById("demo").innerHTML = person.firstName + " is " + person.age + " years old."; Find the type of a variable document.getElementById("demo").innerHTML = typeof "" + "<br>" + typeof "John" + "<br>" + typeof "John Doe" + "<br>" + typeof 0 + "<br>" + typeof 314 + "<br>" + typeof 3.14 + "<br>" + typeof (3.14); Adding two numbers and a string var x = 16 + 4 + "Volvo"; document.getElementById("demo").innerHTML = x; Adding a string and two numbers var x = "Volvo" + 16 + 4; document.getElementById("demo").innerHTML = x; An undefined variable The value (and the data type) of a variable with no value is undefined. var car; document.getElementById("demo").innerHTML = car + "<br>" + typeof car; An empty variable var car = ""; document.getElementById("demo").innerHTML = "The value is: " + car + "<br>" + "The type is: " + typeof car; Create a JavaScript variable var car = "Fiat"; document.getElementById("demo").innerHTML = car; Create a JavaScript object var car = {type:"Fiat", model:"500", color:"white"}; document.getElementById("demo").innerHTML = car.type; Create a person object (single line) var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"}; document.getElementById("demo").innerHTML = person.firstName + " is " + person.age + " years old."; Create a person object (multiple lines) var person = { firstName : "John", lastName : "Doe", age : 50, eyeColor : "blue" }; document.getElementById("demo").innerHTML = person.firstName + " is " + person.age + " years old."; Access object properties using .property var person = { firstName: "John", lastName : "Doe", id: 5566}; document.getElementById("demo").innerHTML = person.firstName + " " + person.lastName; Access object properties using [property] var person = { firstName: "John", lastName : "Doe", id : 5566 }; document.getElementById("demo").innerHTML = person["firstName"] + " " + person["lastName"]; Access a function property as a method var person = { firstName: "John", lastName : "Doe", id : 5566, fullName : function() { return this.firstName + " " + this.lastName; } }; document.getElementById("demo").innerHTML = person.fullName(); Access a function property as a property var person = { firstName: "John", lastName : "Doe", id : 5566, fullName : function() { return this.firstName + " " + this.lastName; }}; document.getElementById("demo").innerHTML = person.fullName; A simple function function myFunction() { document.getElementById("demo").innerHTML = "Hello World!";} A function with an argument function myFunction(name,job) { document.getElementById("demo").innerHTML = "Welcome " + name + ", the " + job + ".";} A function with an argument 2 function myfunction(txt) { document.getElementById("demo").innerHTML = txt} A function that returns a value var x = myFunction(4, 3); document.getElementById("demo").innerHTML = x; function myFunction(a, b) { return a * b;} A function that converts Fahrenheit to Celsius function toCelsius(f) { return (5/9) * (f-32);} document.getElementById("demo").innerHTML = toCelsius(77); A function call without () function toCelsius(f) { return (5/9) * (f-32);} document.getElementById("demo").innerHTML = toCelsius; An onclick event changes an HTML element <button onclick="document.getElementById('demo').innerHTML=Date()">The time is?</button> An onclick event changes its own element <button onclick="this.innerHTML=Date()">The time is?</button> An onclick event calls a function <button onclick="displayDate()">The time is?</button> function displayDate() { document.getElementById("demo").innerHTML = Date(); } Backslash before quotes accepts quotes as quotes. <script> var x = 'It\'s alright'; var y = "We are the so-called \"Vikings\" from the north."; document.getElementById("demo").innerHTML = x + "<br>" + y; </script> Find the length of a string var txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; document.getElementById("demo").innerHTML = txt.length; You can break text string with a backslash. document.getElementById("demo").innerHTML = "Hello \ Dolly!"; You cannot break code with a backslash. document.getElementById("demo").innerHTML = \ "Hello Dolly."; Find the position of the first occurrence of a text in a string - indexOf() var str = "Please locate where 'locate' occurs!"; var pos = str.indexOf("locate"); document.getElementById("demo").innerHTML = pos; Search for a text in a string and return the text if found - match() var str = "The rain in SPAIN stays mainly in the plain"; var res = str.match(/ain/g); document.getElementById("demo").innerHTML = res; Replace characters in a string - replace() var str = document.getElementById("demo").innerHTML; var txt = str.replace("Microsoft","W3Schools"); document.getElementById("demo").innerHTML = txt; Convert string to upper case - toUpperCase() var text = document.getElementById("demo").innerHTML; document.getElementById("demo").innerHTML = text.toUpperCase(); Convert string to lower case - toLowerCase() var text = document.getElementById("demo").innerHTML; document.getElementById("demo").innerHTML = text.toLowerCase(); Split a string into an array - split() var str = "a,b,c,d,e,f"; var arr = str.split(","); document.getElementById("demo").innerHTML = arr[0]; Number are considered accurate only up to 15 digits var x = 999999999999999; var y = 9999999999999999; document.getElementById("demo").innerHTML = x + "<br>" + y; Floating point arithmetic is not always 100% accurate var x = 0.2 + 0.1; document.getElementById("demo").innerHTML = "0.2 + 0.1 = " + x; it helps to multiply and divide by 10 var x = (0.2*10 + 0.1*10) / 10; document.getElementById("demo").innerHTML = "0.2 + 0.1 = " + x; } Constants, preceded by 0x, are interpreted as hexadecimal document.getElementById("demo").innerHTML = "0xFF = " + 0xFF; The toString() method can output numbers as hex, octal, and binary var myNumber = 128; document.getElementById("demo").innerHTML = "128 = " + myNumber + " Decimal, " + myNumber.toString(16) + " Hexadecimal, " + myNumber.toString(8) + " Octal, " + myNumber.toString(2) + " Binary." JavaScript will generate Infinity if you calculate a too large number var myNumber = 2; var txt = ""; while (myNumber != Infinity) { myNumber = myNumber * myNumber; txt = txt + myNumber + "<br>"; } document.getElementById("demo").innerHTML = txt; Division by zero generates Infinity var x = 2/0; var y = -2/0; document.getElementById("demo").innerHTML = x + "<br>" + y; A number divided by a string is not a number var x = 1000 / "Apple"; var y = 1000 / "10"; document.getElementById("demo").innerHTML = x + "<br>" + y; Math.PI returns the value of PI document.getElementById("demo").innerHTML = Math.PI; Math.round(x) returns the rounded value of x document.getElementById("demo").innerHTML = Math.round(4.4); Math.pow(x,y) returns the value of x to the power of y document.getElementById("demo").innerHTML = Math.pow(8,2); Math.sqrt(x) returns the square root of x document.getElementById("demo").innerHTML = Math.sqrt(64); Math.abs(x) returns the absolute (positive) value of x document.getElementById("demo").innerHTML = Math.abs(-4.4); Math.ceil(x) returns the value of x rounded up document.getElementById("demo").innerHTML = Math.ceil(4.4); Math.floor(x) returns the value of x rounded down document.getElementById("demo").innerHTML = Math.floor(4.7); Math.sin(x) returns the sin of the angel x (given in radians) document.getElementById("demo").innerHTML = "The sine value of 90 degrees is " + Math.sin(90 * Math.PI / 180); Math.cos(x) returns the cosin of the angel x (given in radians) document.getElementById("demo").innerHTML = "The cosine value of 0 degrees is " + Math.cos(0 * Math.PI / 180); Math.max() return the number with the highest value from a list of arguments document.getElementById("demo").innerHTML = Math.max(0, 150, 30, 20, -8, -200); Math.min() to return the number with the lowest value from a list of arguments document.getElementById("demo").innerHTML = Math.min(0, 150, 30, 20, -8, -200); =====================

    Find the min/max element of an Array

    Note: These Math functions will not work as-is with arrays of numbers. However, there are some ways around this. var numbers = [1, 2, 3, 4]; Math.max.apply(null, numbers) // 4 Math.min.apply(null, numbers) // 1 A simpler, ES2015 way of accomplishing this is with the new spread operator. var numbers = [1, 2, 3, 4]; Math.max(...numbers) // 4 Math.min(...numbers) // 1 ===================== fill array with consecutive numbers const trainY = []; for(x=0; x<(trainX.length-1); x++){trainY[x] = x+1;} ===================== Converting Celsius to Fahrenheit var x; if (degree == "C") { x = document.getElementById("c").value * 9 / 5 + 32; document.getElementById("f").value = Math.round(x); } else { x = (document.getElementById("f").value -32) * 5 / 9; document.getElementById("c").value = Math.round(x); } Math.random() returns a random number between 0 (included) and 1 (excluded) document.getElementById("demo").innerHTML = Math.random(); How to return a random integer between 0 and 9 (both included) document.getElementById("demo").innerHTML = Math.floor(Math.random() * 10); How to return a random integer between 0 and 10 (both included) document.getElementById("demo").innerHTML = Math.floor(Math.random() * 11); How to return a random integer between 0 and 99 (both included) document.getElementById("demo").innerHTML = Math.floor(Math.random() * 100); How to return a random integer between 0 and 100 (both included) document.getElementById("demo").innerHTML = Math.floor(Math.random() * 101); How to return a random integer between 1 and 10 (both included) document.getElementById("demo").innerHTML = Math.floor(Math.random() * 10) + 1; How to return a random integer between 1 and 100 (both included) document.getElementById("demo").innerHTML = Math.floor(Math.random() * 100) + 1; How to return a random integer between x (included) and y (excluded) return Math.floor(Math.random() * (max - min)) + min; How to return a random integer between x and y (both included) return Math.floor(Math.random() * (max - min + 1) ) + min; Use Date() to display today's date and time var d = new Date(); document.getElementById("demo").innerHTML = d; Use getFullYear() display the year var d = new Date(); document.getElementById("demo").innerHTML = d.getFullYear(); Use getTime() to calculate the number of milliseconds since 1970 var d = new Date(); document.getElementById("demo").innerHTML = d.getTime(); Use setFullYear() to set a specific date var d = new Date(); d.setFullYear(2020); document.getElementById("demo").innerHTML = d; Use toUTCString() to convert today's date (according to UTC) to a string var d = new Date(); document.getElementById("demo").innerHTML = d.toUTCString(); Use getDay() to display the weekday as a number var d = new Date(); document.getElementById("demo").innerHTML = d.getDay(); Use getDay() and an array to display the weekday as a name var d = new Date(); var days = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]; document.getElementById("demo").innerHTML = days[d.getDay()]; Display a clock var today = new Date(); var h = today.getHours(); var m = today.getMinutes(); var s = today.getSeconds(); m = checkTime(m); s = checkTime(s); document.getElementById('txt').innerHTML = h + ":" + m + ":" + s; var t = setTimeout(startTime, 500); } function checkTime(i) { if (i < 10) {i = "0" + i}; // add zero in front of numbers < 10 return i; } Create an array var cars = ["Saab", "Volvo", "BMW"]; document.getElementById("demo").innerHTML = cars; Join two arrays - concat() var myGirls = ["Cecilie", "Lone"]; var myBoys = ["Emil", "Tobias", "Linus"]; var myChildren = myGirls.concat(myBoys); document.getElementById("demo").innerHTML = myChildren; Join three arrays - concat() var arr1 = ["Cecilie", "Lone"]; var arr2 = ["Emil", "Tobias", "Linus"]; var arr3 = ["Robin", "Morgan"]; var myChildren = arr1.concat(arr2, arr3); document.getElementById("demo").innerHTML = myChildren; Join all elements of an array into a string - join() var fruits = ["Banana", "Orange", "Apple", "Mango"]; document.getElementById("demo").innerHTML = fruits.join(" * "); Remove the last element of an array - pop() var fruits = ["Banana", "Orange", "Apple", "Mango"]; document.getElementById("demo1").innerHTML = fruits; fruits.pop(); document.getElementById("demo2").innerHTML = fruits; Add new elements to the end of an array - push() var fruits = ["Banana", "Orange", "Apple", "Mango"]; document.getElementById("demo").innerHTML = fruits; function myFunction() { fruits.push("Kiwi"); document.getElementById("demo").innerHTML = fruits;} Reverse the order of the elements in an array - reverse() var fruits = ["Banana", "Orange", "Apple", "Mango"]; document.getElementById("demo").innerHTML = fruits; function myFunction() { fruits.sort(); fruits.reverse(); document.getElementById("demo").innerHTML = fruits; } Remove the first element of an array - shift() var fruits = ["Banana", "Orange", "Apple", "Mango"]; document.getElementById("demo1").innerHTML = fruits; fruits.shift(); document.getElementById("demo2").innerHTML = fruits; Select elements from an array - slice() array.slice(start, end) The slice() method selects the elements starting at the given start argument, and ends at, but does not include, the given end argument. var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"]; var citrus = fruits.slice(1,3); // Orange, Lemon var myBest = fruits.slice(-3, -1); // Lemon, Apple, Mango document.getElementById("demo").innerHTML = myBest; Sort an array (alphabetically and ascending) - sort() var fruits = ["Banana", "Orange", "Apple", "Mango"]; document.getElementById("demo").innerHTML = fruits; function myFunction() { fruits.sort(); document.getElementById("demo").innerHTML = fruits;} Sort numbers (numerically and ascending) - sort() var points = [40, 100, 1, 5, 25, 10]; document.getElementById("demo").innerHTML = points; function myFunction() { points.sort(function(a, b){return a - b}); document.getElementById("demo").innerHTML = points;} Sort numbers (numerically and descending) - sort() var points = [40, 100, 1, 5, 25, 10]; document.getElementById("demo").innerHTML = points; function myFunction() { points.sort(function(a, b){return b - a}); document.getElementById("demo").innerHTML = points; } Sort numbers (alphabetically and numerically) - sort() var points = [40, 100, 1, 5, 25, 10]; document.getElementById("demo").innerHTML = points; function myFunction1() { points.sort(); document.getElementById("demo").innerHTML = points; } function myFunction2() { points.sort(function(a, b){return a - b}); document.getElementById("demo").innerHTML = points; } Sort numbers in random order - sort() var points = [40, 100, 1, 5, 25, 10]; document.getElementById("demo").innerHTML = points; function myFunction() { points.sort(function(a, b){return 0.5 - Math.random()}); document.getElementById("demo").innerHTML = points; } Sort objects by numeric properties - sort() var cars = [{type:"Volvo", year:2016}, {type:"Saab", year:2001}, {type:"BMW", year:2010}] displayCars(); function myFunction() { cars.sort(function(a, b){return a.year - b.year}); displayCars();} function displayCars() { document.getElementById("demo").innerHTML = cars[0].type + " " + cars[0].year + "<br>" + cars[1].type + " " + cars[1].year + "<br>" + cars[2].type + " " + cars[2].year;} Sort objects by string properties - sort() var cars = [ {type:"Volvo", year:2016}, {type:"Saab", year:2001}, {type:"BMW", year:2010}] displayCars(); function myFunction() { cars.sort(function(a, b){ var x = a.type.toLowerCase(); var y = b.type.toLowerCase(); if (x < y) {return -1;} if (x > y) {return 1;} return 0; }); displayCars();} function displayCars() { document.getElementById("demo").innerHTML = cars[0].type + " " + cars[0].year + "<br>" + cars[1].type + " " + cars[1].year + "<br>" + cars[2].type + " " + cars[2].year; } Add an element to position 2 in an array - splice() var fruits = ["Banana", "Orange", "Apple", "Mango"]; document.getElementById("demo").innerHTML = fruits; function myFunction() { fruits.splice(2, 0, "Lemon", "Kiwi"); document.getElementById("demo").innerHTML = fruits;} Convert an array to a string - toString() var fruits = ["Banana", "Orange", "Apple", "Mango"]; document.getElementById("demo").innerHTML = fruits.toString(); Add new elements to the beginning of an array - unshift() var fruits = ["Banana", "Orange", "Apple", "Mango"]; document.getElementById("demo").innerHTML = fruits; function myFunction() { fruits.unshift("Lemon"); document.getElementById("demo").innerHTML = fruits; } Note: fruits.unshift("Lemon"); but not: fruits = fruits.unshift("Lemon"); ===========================

    Creating Keyboard Shortcuts in JavaScript

    Using Plain JavaScript <h3>Press M key on keyboard(Single key)</h3> <h3>Press Ctrl + B shortcut key (Double key combination)</h3> <h3>Press Ctrl + Alt + Y shortcut key (Multiple key combination)</h3> <h3>Press Ctrl + Alt + Shift + U shortcut key (Multiple key combination)</h3> Add script tag before the closing tag of body tag and put in the below script. document.onkeyup = function(e) { if (e.which == 77) { alert("M key was pressed"); } else if (e.ctrlKey && e.which == 66) { alert("Ctrl + B was pressed"); } else if (e.ctrlKey && e.altKey && e.which == 89) { alert("Ctrl + Alt + Y was pressed"); } else if (e.ctrlKey && e.altKey && e.shiftKey && e.which == 85) { alert("Ctrl + Alt + Shift + U was pressed"); } }; for cross browser compatibility you can use something like this. var key = e.which || e.keyCode; Here 77, 66, 89, 85 are the key code representations ctrlKey, shiftKey and altKey are the read-only properties which hold boolean information about these keys. This was using plain JavaScript. Now let’s try this using jQuery. Using jQuery For this example, let’s create a simple Login page, which displays a message whenever Caps Lock is ON. <h3 class="container">Displays message whenever CAPS LOCK is ON</h3> <div class="container-fluid content"> <form class="form-horizontal"> <div class="form-group"> <input type="text" class="form-control" placeholder="Username"> </div> <div class="form-group"> <input type="password" class="form-control" placeholder="Password"> </div> <div id="message" class="form-group"> <p>Caps lock is ON</p> </div> <div class="form-group"> <button type="submit" class="btn btn-primary">Sign in</button> </div> </form> </div> Now coming to the JS part of the code, initially we want the ‘message’ to be hidden. So include this, $('#message').hide(); Now to find out whether the Caps Lock is On or not, simply use a keypress event, so whenever the user presses a key, the keycode information is extracted and checked whether it is in lower case or upper case. Based on this the message is made visible. The code should look something like this. $(document).ready(function() { $('#message').hide(); }) $('.form-control').keypress(function(e) { var c = String.fromCharCode(e.which); if (c.toUpperCase() === c && c.toLowerCase() !== c && !e.shiftKey) { $('#message').show(); } else { $('#message').hide(); } }); In the above code shift, key property is also checked, to see whether shift key was pressed along with another key. The only issue with the above code is, it displays the message whenever a character is pressed and not when the caps lock key is pressed. The KeyCode Finder In the first example, we used key codes like 77, 66, 89, and 85. This example helps you to find out these keycodes. I have a created a pen for this example, just press the desired key and it will display the key code associated with that key. Using Mousetrap.js Imagine a situation where there are a lot of shortcut keys to be implemented in a page, using above methods is not feasible. For example in a cloud-based IDE, there are a lot of shortcut keys used. So this can be simplified using the JS library Mousetrap.js. The CDN link is here. I have created a simple pen for this example. Here, in this example Mousetrap.bind function is used. This function binds a key combination with a callback function. There are some other functionalities also with this library. Read about all of them here. Conclusion All these above examples explained how to use keyboard shortcuts in JS. The Mousetrap library simplifies this whole process by just using bind method. There are many other libraries like KeyboardJS, Keypress or Keymaster which all do almost the same thing. JavaScriptWeb DevelopmentKeyobard ShortcutsMousetrapjs ===========================

    search text inside page


    <input type="text" id="searchText" value="美容"> <button onclick="searchIt()">查找</button> <p id="searchResult"></p> function searchIt() {searchResultList = "查找結果: ";var featureStr = document.getElementById("searchText").value;$("div").each(function(i) { drugName = $(this).children("b").text(); drugFunc = $(this).text(); if (drugFunc.includes(featureStr)) { searchResultList = searchResultList + drugName + ", "; }});document.getElementById("searchResult").innerHTML = searchResultList; } ===========================

    search link ID inside page


    $(document).ready(function(){ $('div b').click(function(){ parent.history.back(); return false; }); }); document.querySelector('#searchText').focus(); $('#searchText').keyup(function(e) {if (e.keyCode === 13) {searchIt();}}); function searchIt() {searchResultList = "查找結果: ";var featureStr = document.getElementById("searchText").value;$("div").each(function(i) { drugName = $(this).children("b").text(); drugNameID = $(this).children("b").attr('id'); drugFunc = $(this).text(); drugDetail = drugName + drugFunc; if (drugDetail.includes(featureStr)) { theLink = '<a href="#' + drugNameID + '" target="_self">' + drugName + '</a>, '; searchResultList = searchResultList + theLink; }});document.getElementById("searchResult").innerHTML = searchResultList; }
    ===========================

    轉繁體 轉簡體


    <script type="text/javascript" src="https://www.ifreesite.com/1-plus/gbkbig5.js"></script> <form name="biggbks"> <input onClick="s2t()" type="button" value="轉繁體"> <input onClick="t2s()" type="button" value="轉簡體"> <textarea name="text" id="text" rows="1" cols="40" onKeyUp="changeText(this);"></textarea><div class="tops"> <input type="button" value="復原" onClick="undo()" /> <input onClick="blank()" type="button" value="清除" /></div> </form> ===========================

    To refresh page using javascript instead of meta tag:


    refreshTime = 2000; // reload page after 2 seconds setTimeout(function() { location.reload(); },refreshTime); ===========================

    JaveScript to iterate over localStorage browser object

    for (var i = 0; i < localStorage.length; i++){ key=localStorage.key(i); console.log(key+': '+localStorage.getItem(key)); }

    Advanced script

    As mentioned here a HTML5 featured browser should also implement Array.prototype.map. So script would be: Array.apply(0, new Array(localStorage.length)).map(function(o, i){ return localStorage.key(i)+':'+localStorage.getItem(localStorage.key(i)); }) ===========================

    html5 localStorage

    localStorage only supports strings. Use JSON.stringify() and JSON.parse(). var names = []; names[0] = prompt("New member name?").setItem("names", JSON.stringify(names)); //... var storedNames = JSON.parse(localStorage.getItem("names")); ========= localStorage.setItem("objName", "PeterPan") localStorage.getItem("objName") localStorage.length localStorage.key(0); localStorage.removeItem("objName") localStorage.heedCode="test code" localStorage.removeItem("heedCode") localStorage.setItem("heedCode", "00PeterPan") heedCodeList = ["372","1800"] localStorage.savedCodeList = JSON.stringify(heedCodeList); oldheedCodeList = JSON.parse(localStorage.savedCodeList) oldheedCodeList[0] oldheedCodeList[1] if (localStorage.getItem("savedCodeList") === null) { heedCodeList = []; localStorage.savedCodeList = JSON.stringify(heedCodeList); } else{ heedCodeList = JSON.parse(localStorage.savedCodeList); } ========= var jsonData = JSON.parse(document.getElementById('data').textContent) ========= $.getJSON("https://api.github.com/users/jeresig"); ========= localStorage namespace one localStorage for each subdomain. Local Storage is prone to name clashes and accidental data overrides A simple solution is to prefix all your app specific keys with your unique project name several applications run on the same protocol/server/port, but with a different url, they will have access to the same localstorage. if keys are using names that any other developer might use like "user", "data", "cache", you might end up reading localstorage from another application altogether. If that app is running on the same server. Total amount of data that can be stored is limited per domain ===========================

    localStorage.savedCodeList

    if (localStorage.getItem("savedCodeList") === null) { heedCodeList = []; localStorage.savedCodeList = JSON.stringify(heedCodeList); } else{ heedCodeList = JSON.parse(localStorage.savedCodeList); } localStorage.savedCodeList = JSON.stringify(heedCodeList); heedChart heedChart.html if (!heedCodeList.includes(stkChartList[remainChtNo])) { heedCodeList.push(stkChartList[remainChtNo]); heedCodeList = Array.from(new Set(heedCodeList)) localStorage.savedCodeList = JSON.stringify(heedCodeList); }

    execCommand

    copyText = JSON.stringify(stkChartList); copyText.select(); document.execCommand("copy"); The execCommand() method executes the specified command for the selected part of an editable section.

    window width

    var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); 740 814 var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); 572 177309 document.documentElement.clientWidth document.documentElement.clientHeight $(window).width() and $(window).height()

    setFontSize

    function setFontSize(size) { $.cookie('fontsize', size, { path: '/' }); window.location.reload(); }

    swiperight

    $("body").on("swiperight",function(){ jpButClick(); }); $("body").on("swipeleft",function(){ jpback(); });

    Regex To match all occurences using /g

    1. var str = "The rain in SPAIN stays mainly in the plain"; var res = str.match(/ain/g); 2. var msg = "For example, /green|red/ matches 'green' in 'green apple' and 'red' in 'red apple.' The order of 'x' and 'y' matters. For example a*|b matches the empty string in 'b', but b|a* matches 'b' in the same string." var result = msg.match(/green|red/g) 3. re = /green|red/g var all_matches = msg.match(re); console.log(all_matches) 4. To list out the object structure using JSON.stringify str = JSON.stringify(result); str = JSON.stringify(result, null, 4); // (Optional) beautiful indented output. console.log(str); 5. Some more tips: Object.keys(result); Object.getOwnPropertyNames(result); result.length; =================================== var patt = /w3schools/i Example explained: /w3schools/i is a regular expression. w3schools is a pattern (to be used in a search). i is a modifier (modifies the search to be case-insensitive). Modifiers Modifiers are used to perform case-insensitive and global searches: Modifier Description g global match (find all matches, no stopping after first match) i Perform case-insensitive matching m Perform multiline matching Brackets Brackets are used to find a range of characters: Expression Description [abc] Find any character between the brackets [^abc] Find any character NOT between the brackets [0-9] Find any character between the brackets (any digit) [^0-9] Find any character NOT between the brackets (any non-digit) (x|y) Find any of the alternatives specified ===========================

    swipeleft swiperight

    <script src="https://code.jquery.com/jquery-1.11.3.min.js"></script> <script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script> $("body").on("swiperight",function(){foreward(); }); $("body").on("swipeleft",function(){backward(); }); $("body").on("swiperight",function(){jpButClick(); }); $("body").on("swipeleft",function(){jpback(); }); ===========================

    copy text to clipboard

    var copyTextarea = document.querySelector('.copytextarea1'); copyTextarea.focus(); copyTextarea.select(); // to get element's textContent itemTxt = document.querySelector('.js-tip').textContent ===========================

    nice font

    <link href='https://fonts.googleapis.com/css?family=Architects+Daughter' rel='stylesheet' type='text/css'> ===========================

    tutorial Notes from LearnWebCode

    Javascript tutorial Notes from LearnWebCode
    browser developer mode window object is the root object document object is under window object, all about the html document.title is the title object use getElementById("") to select object use var to represent the object to avoid long typings use .innerHTML() to read and set object content use getElementsByClassName("") to select multiple elements use getElementById("").getElementByTagName("") to select a group under a object access element under a group object: object[0], object is an array for loop: for (){} listItems.length is length of the object addEventListener("click", aFunction) set function using keyword: function aFunction(){} use keyword: this to select the selected item, eg. this.innerHTML; to append element to an group object, use ourList.innerHTML += "something new"; to increment a counter, use theCounter++; this.classList.add("active") The Element.classList is a collection of the class attributes, classes and be added, remove or toggle Event delegate 是 event binding 的一種技巧 Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future. ourList.addEventListener("click", aFunction) aFunction(e){ if(e.target.nodeName == ) } e.target is complicated mordern selector use querySelector("#id") instead of getelementById... querySelectorAll("#id li") ===========================

    HTMLAudioElement interface

    Web Audio APIImp Audio Visualizer audio-visualizer var audio = new Audio('audio_file.mp3'); audio.play(); var snd = new Audio("http://www.externalharddrive.com/waves/computer/hello.wav"); snd.play(); ===========================

    Load TensorFlow.js

    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.12.0"> </script> ===========================

    const

    const The value of a constant cannot change through re-assignment, and it can't be redeclared. The const declaration creates a read-only reference to a value whose scope can be either global
    ===========================

    parsing python code to javascript

    skulpt is doing exactly the same thing as brython and pyjs - parsing python code to javascript not running it natively in the browser ===========================

    inheritance

    JavaScript inheritance is simpler var some2dPoint = {x:3,y:5}; var now3d = Object.create(some2dPoint); now3d.z=10 ===========================

    selection script

    <select id="myChoice" onchange="showChoice()"><option>Apple</option><option>Orange</option><option>Pineapple</option><option>Banana</option> </select> <p id="demo"></p> <script> function showChoice() {var x = document.getElementById("myChoice");var i = x.selectedIndex;document.getElementById("demo").innerHTML = x.options[i].text; } </script> ===========================

    jQuery Object and HTML DOM Object

    In jQuery, to get the same result as document.getElementById, access the jQuery Object and get the first element in the object document.getElementById('contents'); //returns a HTML DOM Object var contents = $('#contents'); //returns a jQuery Object var contents = $('#contents')[0]; //returns a HTML DOM Object Javascript 跟 JQuery
    To get the DOM object(s) from the jQuery one, use the following: $('#selectlist').get(); //get all DOM objects in the jQuery collection $('#selectlist').get(0); //get the DOM object in the jQuery collection at index 0 $('#selectlist')[0]; //get the DOM objects in the jQuery collection at index 0 ===========================

    fibonacci function

    function fibonacci(num){ var a = 1, b = 0, temp; var seq = [] while (num > 0){ temp = a; a = a + b; b = temp; seq.push(b) num--; } return seq; } const fibs = fibonacci(100) ===========================

    input numeric filter

    var numericExpression = /^[0-9]+$/; if(!userInput.match(numericExpression)){alert("Please enter a number")} ===========================

    some timer codes

    <input type="number" id="hourtimer"> <input type="number" id="minutetimer" autofocus> <input type="number" id="secondtimer"> function cvtToMinAndSecStr( x ) {return Math.floor(x/60) + ":" + x%60;} function displayMsg( noticeArea, msg ) {document.getElementById(noticeArea).innerHTML = msg;} if(displaySeconds < 10) {displaySeconds = '0' + displaySeconds;} let timeRemaining = 0; let timer; function starttimer() { if( ! timer) { timer = setInterval(function() {timeRemaining = timeRemaining - 1; displayTime();}, 1000); } } countdown.innerText = hours + ":" + minutes + ":" + displaySeconds; ===========================

    numerical input value step attribute

    The step attribute can be used with a numerical input value to dictate how granular the values you can input are. <input type="time" id="timerInput" step="1"> document.getElementById("settime").value = "13:24:59"; For example, you might want users to enter a particular time, but only in 30 minute increments. In this case, we can use the step attribute, keeping in mind that for time inputs the value of the attribute is in seconds. For example, a 30 minute increment would have a step value of 1800. <input type="time" step="1800"> Return the value property: timeObject.value Set the value property: timeObject.value = hh:mm:ss.ms function myFunction() { var x = document.createElement("INPUT"); x.setAttribute("type", "time"); x.setAttribute("value", "21:35:09"); document.body.appendChild(x); }

    script to animate css

    <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css'> ===========================

    Math.floor(Math.random...

    listLen = Math.floor(Math.random() * (listLen -1)); ===========================

    Include JavaScript file

    appendChild() is a more native way: var script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'script.js'; document.head.appendChild(script); var script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.12.0'; document.head.appendChild(script); ====================== Using jQuery: $.getScript('script.js'); ====================== use the fetch: fetch('https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js') .then(response => response.text()) .then(text => eval(text)) .then(() => { /* now you can use your library */ }) ====================== https://stackoverflow.com/questions/5282228/include-javascript-file-in-chrome-console ======================

    check time falls within a specific range

    check time falls within a specific range function checkTime() { var d = new Date(); // current time var hours = d.getHours(); var mins = d.getMinutes(); var day = d.getDay(); return day >= 1 && day <= 5 && hours >= 9 && (hours < 17 || hours === 17 && mins <= 30); } function checkTime() { var d = new Date(); // current time var hours = d.getHours(); var mins = d.getMinutes(); var day = d.getDay(); return day >= 1 && day <= 5 && (hours >= 9 || hours === 9 && mins >= 30) && (hours < 12) && (hours >= 13) && (hours < 16); } ===========================

    create a dataset

    var dataset = []; var count =10; for (var j = 0; j < count; j++) {dataset[j] = Math.round(Math.random() * 100)}

    polar and cartesian coordinates

    function d_Btw_2Pts(x1, y1, x2, y2) {// Pythagoras Theoremvar x = (x2-x1);var y = (y2-y1);return Math.sqrt(x*x + y*y); } function polar2Cart(R, theta) {x = R * Math.cos(theta);y = R * Math.sin(theta);return [x,y] }

    convert to fixed decimal places

    num.toFixed(2);

    get image size height width using javascript

    var image = document.getElementById('imagearea'); alert(image.clientWidth, image.clientHeight); clientWidth and clientHeight are DOM properties that show the current in-browser size of the inner dimensions of a DOM element (excluding margin and border). So in the case of an IMG element, this will get the actual dimensions of the visible image. img.onload = function() { alert(this.width + 'x' + this.height); } get image size height width using javascript

    generate random number that is negative or positive

    (Math.random()-1/2)*2

    js script load external script

    $.getScript('another_file.js', function() { //script is loaded and executed put your dependent JS here }); or var imported = document.createElement('script'); imported.src = '/path/to/imported/script'; document.head.appendChild(imported);

    Dynamically load JS

    var script = document.createElement('script'); script.onload = function() { //do stuff with the script }; script.src = something; document.head.appendChild(script);

    Convert unicode character to string format

    Convert unicode character to string format
    theStr = "\u9999\u6e2f\u98df\u54c1\u6295\u8d44" // this will show correctly as "香港食品投资" String.fromCharCode(parseInt("6e2f",16)) //this work String.fromCharCode(parseInt("9999 6e2f 98df 54c1 6295 8d44",16)) //cannot work

    Learn API

    Learn API docs

    Vibration API Sample

    Vibration API Sample
    function example1() { // Vibrate for 500ms navigator.vibrate([500]); }

    worker

    const delay = 5000; // run without worker const withoutWorkerButton = document.createElement('button'); document.body.appendChild(withoutworkerButton); withoutWorkerButton.textContent = 'without Worker'; withoutWorkerButton.addEventListener('click', ()=> {const start = performance.now();while (performance.now() - start < delay);const end = performance.now();console.log(end-start); });// run with worker const myworker = new worker('./worker.js') // create worker myworker.onMessage = e => {console.log('myworker says: ', e.data); } const withWorkerButton = document.createElement('button'); document.body.appendChild(withworkerButton); withWorkerButton.textContent = 'with Worker'; withWorkerButton.addEventListener('click', ()=> {myworker.postMessage(delay); }); //worker.js this.onMessage = e => {const delay = e.data;const start = performance.now();while (performance.now() - start < delay);const end = performance.now();this.postMessage(end-start); } performance now vs date now
    Performance API

    Use Indirect Variables, 'Variable' variables in Javascript

    Indirect Variables or dynamic variable names Javascript Use Indirect Variables, 'Variable' variables in Javascript // example // global var vara0='a'; var varb0='b'; alert(window['vara'+0]); // gives 'a' alert(window['varb'+0]); // gives 'b' console.log(window['vara'+0]); console.log(window['varb'+0]); // example var foos = ['foo', 'bar', 'baz']; for(i=0; i<foos.length; i++){ console.log(foos[i]); } Note: eval() is heavy handed. eval() uses lots of cpu resources. try to avoid it. // example // local function foo(){var var1='b';alert(eval('var'+1)) } foo() // example var foo = 42; var bar = 21; var key = 'foo'; console.log(eval(key)); variable variables in javascript
    In programming, dynamic variable names don’t have a specific name hard-coded in the script. They are named dynamically with string values from other sources. Dynamic variables are rarely used in JavaScript. But in some cases they are useful. Unlike PHP, there is no special implementation of dynamic variable names in JavaScript. But similar results can be achieved by using some other methods. In JavaScript, dynamic variable names can be achieved by using 2 methods/ways given below. eval() Method: The eval() function evaluates JavaScript code represented as a string in the parameter. A string is passed as a parameter to eval(). If the string represents an expression, eval() evaluates the expression. Inside eval(), we pass a string in which variable value i is declared and assigned a value of i for each iteration. The eval() function executes this and creates the variable with the assigned values. The code is given below implements the creation of dynamic variable names using eval(). Example: var k = 'value'; var i = 0; for(i = 1; i < 3; i++) { eval('var ' + k + i + '= ' + i + ';'); } console.log(value1); console.log(value2); Output: value1=1 value2=2 Window object: JavaScript always has a global object defined. When the program creates global variables they’re created as members of the global object. The window object is the global object in the browser. Any global variables or functions can be accessed with the window object. After defining a global variable we can access its value from the window object. The code given below implements dynamic variable names using the window object. So, the code basically creates a global variable with dynamic name “valuei” for each iteration of i and assigns a value of i to it. Later these variables can be accessed in the script anywhere as they become global variables. Example: var i; for(i = 1; i < 3; i++) { window['value'+i] = + i; } console.log(value1); console.log(value2); Output: value1=1 value2=2 // use global variable var var1='c'; alert(window['var'+ 1]); // c // use eval var1 = "b" thisvar = "var" + 1 alert (eval(thisvar)) ignoreLstName = bookid + "IgnoreLst" window["ignoreLstName"] // note the " to use global variable eval("ignoreLstName") // use eval example bookid = "中医Tips" ignoreLstName = bookid + "IgnoreLst" if (localStorage.getItem(window["ignoreLstName"]) === null) { localStorage.setItem(window["ignoreLstName"], ""); ignoreLst = [] } else{ ignoreLst = localStorage.getItem(window["ignoreLstName"]).split(','); } Evaluating JavaScript code via eval() and new Function()

    Emit a beep sound

    // browsers limit the number of concurrent audio contexts, so better re-use them audi = new AudioContext(); function beep(vol, freq, duration){ v = audi.createOscillator() u = audi.createGain() v.connect(u) v.frequency.value = freq v.type = "square" u.connect(audi.destination) u.gain.value = vol*0.01 v.start(audi.currentTime) v.stop(audi.currentTime + duration*0.001) } beep(50,500,600) // to loop with diff freq function start( counter ){ if( counter < 20){ setTimeout( function(){ counter++; console.log(counter); beep(350, counter*50, 400); start(counter); }, 500); } } start(0);

    Delay, Sleep, Pause, & Wait in JavaScript

    Many programming languages have a sleep function that will delay a program’s execution for a given number of seconds. This functionality is absent from JavaScript, however, owing to its asynchronous nature. The standard way of creating a delay in JavaScript is to use its setTimeout method. console.log("Hello"); setTimeout(() => { console.log("World!"); }, 2000); Waiting for Things with setTimeout function pollDOM () { const el = document.querySelector('my-element'); if (el.length) { // Do something with el } else { setTimeout(pollDOM, 300); // try again in 300 milliseconds } } pollDOM(); Flow Control in Modern JavaScript It’s often the case when writing JavaScript that we need to wait for something to happen (for example, data to be fetched from an API), then do something in response (such as update the UI to display the data). The example above uses an anonymous callback function for this purpose, but if you need to wait for multiple things to happen, the syntax quickly gets pretty gnarly and you end up in callback hell. Luckily, the language has evolved considerably over the past few years and now offers us new constructs to avoid this. For example, using async await we can rewrite the initial code to fetch information from the GitHub API: (async () => { const res = await fetch(`https://api.github.com/users/jameshibbard`); const json = await res.json(); console.log(json.public_repos); console.log("Hello!"); })(); Now the code executes from top to bottom. The JavaScript interpreter waits for the network request to complete and the number of public repos is logged first, then the “Hello!” message. Bringing Sleep to Native JavaScript function sleep(milliseconds) { const date = Date.now(); let currentDate = null; do { currentDate = Date.now(); } while (currentDate - date < milliseconds); } console.log("Hello"); sleep(2000); console.log("World!"); As expected, this will log “Hello”, pause for two seconds, then log “World!” it has a large disadvantage: the loop will block JavaScript’s execution thread and ensure that nobody can interact with your program until it finishes. If you need a large delay, there’s a chance that it may even crash things altogether. A Better Sleep Function Well, it’s also possible to combine the techniques to make a less intrusive sleep function: function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } console.log("Hello"); sleep(2000).then(() => { console.log("World!"); }); Notice that we need to use a then callback to make sure the second message is logged with a delay. We can also chain more callbacks onto the first: console.log("Hello"); sleep(2000) .then(() => { console.log("World!"); }) .then(() => { sleep(2000) .then(() => { console.log("Goodbye!"); }) }); This works, but looks ugly. We can pretty it up using async ... await: function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function delayedGreeting() { console.log("Hello"); await sleep(2000); console.log("World!"); await sleep(2000); console.log("Goodbye!"); } delayedGreeting(); This looks nicer, but means that whatever code is using the sleep function needs to be marked as async. Of course, both of these methods still have the disadvantage (or feature) that they do not pause the entire program execution. Only your function sleeps: function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function delayedGreeting() { console.log("Hello"); await sleep(2000); console.log("World!"); } delayedGreeting(); console.log("Goodbye!"); JavaScript’s asynchronous nature is quite nice when you get used to it. simple delay function delay(time) { return new Promise(resolve => setTimeout(resolve, time)); }

    reminders notes

    reminders add, remove, edit notes notes object format: date, time, details, remind frequency (repeating), action sort date time sequence use set interval calc current time and set interval array of objects: remindList remindList = [] var remindNotes = new Object(); remindNotes.date = 'date'; remindNotes.time = 'timw'; remindNotes.details = "description'; remindNotes.freq = 1; remindNotes.interval = 2; remindNotes.action = beep;

    RegEx text manipulations

    Practical JavaScript Regular Expressions Syntax: /pattern/modifiers; /pattern/ is the regular expression pattern e.g. /.*abcd/ modifiers is the followings: i Perform case-insensitive matching g Perform a global match (find all matches rather than stopping after the first match) m Perform multiline matching JavaScript String Reference simple methods: str.search()var str = "Please locate where 'locate' occurs!";var pos = str.search("locate");str.replace()str = "Please visit Microsoft!";var n = str.replace("Microsoft", "W3Schools");String Lengthvar txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";var theTxtLen = txt.length;Finding a String in a Stringvar str = "Please locate where 'locate' occurs!";var pos = str.indexOf("locate");Extracting String Parts: 3 methods for extracting part of a stringslice(start, end)substring(start, end)substr(start, length)toUpperCase() toLowerCase() concat() trim()var str = " Hello World! ";alert(str.trim()); split()var txt = "a,b,c,d,e"; // Stringtxt.split(","); // Split on commastxt.split(" "); // Split on spacestxt.split("|"); // Split on pipee.g. var thestr = 'FLSZ 1070560 - 00700腾讯控股'; var regex = /.* - /; str = thestr.replace(regex, ""); console.log(str.slice(0, 4)); Regular Expression Patterns [abc] Find any of the characters between the brackets [^abc] Find any character NOT between the brackets [0-9] Find any character between the brackets (any digit) [^0-9] Find any character NOT between the brackets (any non-digit) (x|y) Find any of the alternatives specified Metacharacter Description Try it . Find a single character, except newline or line terminator \w Find a word character \W Find a non-word character \d Find a digit \D Find a non-digit character \s Find a whitespace character \S Find a non-whitespace character \b Find a match at the beginning/end of a word \B Find a match not at the beginning/end of a word \0 Find a NUL character \n Find a new line character \f Find a form feed character \r Find a carriage return character \t Find a tab character \v Find a vertical tab character \xxx Find the character specified by an octal number xxx \xdd Find the character specified by a hexadecimal number dd \uxxxx Find the Unicode character specified by a hexadecimal number xxxx Quantifier Description n+ Matches any string that contains at least one n n* Matches any string that contains zero or more occurrences of n n? Matches any string that contains zero or one occurrences of n n{X} Matches any string that contains a sequence of X n's n{X,Y} Matches any string that contains a sequence of X to Y n's n{X,} Matches any string that contains a sequence of at least X n's n$ Matches any string with n at the end of it ^n Matches any string with n at the beginning of it ?=n Matches any string that is followed by a specific string n ?!n Matches any string that is not followed by a specific string n RegExp Object exec() Tests for a match in a string. Returns the first match test() Tests for a match in a string. Returns true or false toString() Returns the string value of the regular expression RegExp Object Properties constructor Returns the function that created the RegExp object's prototype global Checks whether the "g" modifier is set ignoreCase Checks whether the "i" modifier is set lastIndex Specifies the index at which to start the next match multiline Checks whether the "m" modifier is set source Returns the text of the RegExp pattern Example var str = "Visit W3Schools!"; var pat = /o/g; var n = str.match(pat); n.length;

    regular expressions substitute operator $1-$9

    The non-standard $1, $2, $3, $4, $5, $6, $7, $8, $9 properties are static and read-only properties of regular expressions that contain parenthesized substring matches. var str = 'asd-0.testing'; var regex = /(asd-)\d(\.\w+)/; str = str.replace(regex, "$11$2"); "asd-1.testing" str = str.replace(regex, "$13$2"); "asd-3.testing"

    convert seconds to colon-separated time string (hh:mm:ss)

    var date = new Date(null); date.setSeconds(45); // specify value for SECONDS here var timeString = date.toISOString().substr(11, 8); console.log(timeString) thisDate = new Date() Sun Feb 24 2019 14:22:58 GMT+0800 (Hong Kong Standard Time) thisDate.toTimeString() "14:22:58 GMT+0800 (Hong Kong Standard Time)" thisDate.replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1") thisDate.replace is not a function thisDate.toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1") "14:22:58"

    iterators and generators

    The for loop could be written like this: const possiblePrimes = [73, 6, 90, 19, 15]; const confirmedPrimes = []; for (const i of possiblePrimes){ if ( isPrime(i) ){ confirmedPrimes.push(i); } } // confirmedPrimes is now [73, 19] This is far cleaner, but the most striking bit of this is the for loop. The variable i now represents the actual item in the array called possiblePrimes. So, we don’t have to call it by index anymore. This means that instead of calling possiblePrimes[i] in the loop, we can just call i. Behind the scenes, this kind of iteration is making use of ES6’s bright and shiny Symbol.iterator() method. This bad boy is in charge of describing the iteration and, when called, returns a JavaScript object containing the next value in the loop and a done key that is either true or false depending on whether or not the loop is finished. Generators Generators, also called “iterator factories”, are a new type of JavaScript function that creates specific iterations. They give you special, self-defined ways to loop over stuff. Okay, so what does all that mean? Let’s look at an example. Let’s say that we want a function that will give us the next prime number every time we call it. Again, we’ll use our isPrime function from before to check if a number is prime: function* getNextPrime() { let nextNumber = 2; while (true) { if (isPrime(nextNumber)) { yield nextNumber; } nextNumber++; } } If you’re used to JavaScript, some of this stuff will look a bit like voodoo, but it’s actually not too bad. We have that strange asterisk after the keyword function, but all this does is to tell JavaScript that we’re defining a generator. The other funky bit would be the yield keyword. This is actually what a generator spits out when you call it. It’s roughly equivalent to return, but it keeps the state of the function instead of rerunning everything whenever you call it. It “remembers” its place while running, so the next time you call it, it carries on where it left off. This means that we can do this: const nextPrime = getNextPrime(); And then call nextPrime whenever we want to obtain — you guessed it — the next prime: console.log(nextPrime.next().value); // 2 console.log(nextPrime.next().value); // 3 console.log(nextPrime.next().value); // 5 console.log(nextPrime.next().value); // 7 You can also just call nextPrime.next(), which is useful in situations where your generator isn’t infinite, because it returns an object like this: console.log(nextPrime.next()); // {value: 2, done: false} Here, that done key tells you whether or not the function has completed its task. In our case, our function will never finish, and could theoretically give us all prime numbers up to infinity (if we had that much computer memory, of course). javascript iterables, iterators, and generators


    countDecimals and transformations

    function countDecimals(value) { if ((value % 1) != 0) return value.toString().split(".")[1].length; return 0; }; avalue = 1.0320 avalue *= 10 apowval = 1 apowval ++ avalue = 1.0320 a = countDecimals(avalue) amplified = avalue*Math.pow(10, a); original = amplified/Math.pow(10, a);

    Higher Order Functions: Filter, Map and Reduce

    Intro
    Filter
    Map
    Reduce
    Combining map, filter and reduce

    Intro

    Higher Order Functions: Using Filter, Map and Reduce for More Maintainable Code repeat executing function on array element .map(Number) Calls Number on each value in the array (casting it to a number) .filter() filter on each element in the array does not change the original array. use .reduce() to create our own implementation of .map() and .filter() var arr = [ 1, 2, 3 ]; var arrDoubled = arr.map(function(x) { return x * 2; }); console.log(arrDoubled); // [ 2, 4, 6 ] Higher order functions can also return a function. For example, you can make a function called multiplyBy that takes a number and returns a function that multiplies another number you provide by the first number provided. You can use this approach to create a multiplyByTwo function to pass to Array.map. function multiplyBy(num1) { return function(num2) { return num1 * num2; } } var multiplyByTwo = multiplyBy(2); var arr = [ 1, 2, 3 ]; var arrDoubled = arr.map(multiplyByTwo); console.log(arrDoubled); // [ 2, 4, 6 ] It also makes it easy to combine functions with each other. This is called composition The three most used higher order functions in JavaScript are .filter(), .map() and .reduce().

    Filter

    Imagine writing a piece of code that accepts a list of people where you want to filter out the people that are equal or above the age of 18. Our list looks like the one below: const people = [ { name: ‘John Doe’, age: 16 }, { name: ‘Thomas Calls’, age: 19 }, { name: ‘Liam Smith’, age: 20 }, { name: ‘Jessy Pinkman’, age: 18 }, ]; Let’s look at an example of a first order function which select people that are above the age of 18. const peopleAbove18 = (collection) => { const results = []; for (let i = 0; i < collection.length; i++) { const person = collection[i]; if (person.age >= 18) { results.push(person); } } return results;}; Now what if we want to select all the people who are between 18 and 20? We could create another function. const peopleBetween18And20 = (collection) => { const results = []; for (let i = 0; i < collection.length; i++) { const person = collection[i]; if (person.age >= 18 && person.age <= 20) { results.push(person); } } return results; }; You may already recognize a lot of repeating code here. This could be abstracted into a more generalized solution. These two functions have something in common. They both iterate over a list and filter it on a given condition.
    “A higher order function is a function that takes one or more functions as arguments.”Closurebridge
    We can improve our previous function by using a more declarative approach, .filter(). const peopleAbove18 = (collection) => { return collection.filter((person) => person.age >= 18);} That’s it! We can reduce a lot of extra code by using this higher order function. It also make our code better to read. We don’t care how things are being filtered, we just want it to filter. I will go into combining functions later in this article.

    Map

    Let’s take the same list of people and an array of names that tells if the person loves to drink coffee. const coffeeLovers = [‘John Doe’, ‘Liam Smith’, ‘Jessy Pinkman’]; The imperative way will be like: const addCoffeeLoverValue = (collection) => { const results = []; for (let i = 0; i < collection.length; i++) { const person = collection[i]; if (coffeeLovers.includes(person.name)) { person.coffeeLover = true; } else { person.coffeeLover = false; } results.push(person); } return results; }; We could use .map() to make this more declarative. const incrementAge = (collection) => { return collection.map((person) => { person.coffeeLover = coffeeLovers.includes(person.name); return person; }); }; Again, .map() is a high-order function. It allows a function to be passed as an argument.

    Reduce

    I bet you will like this function when you know when and how to use it. The cool thing about .reduce() is that most of the functions above can be made with it. Let’s take a simple example first. We want to sum up all the people’s ages. Again, we’ll look how this can be done using the imperative approach. It’s basically looping through the collection and increment a variable with the age. const sumAge = (collection) => { let num = 0; collection.forEach((person) => { num += person.age; }); return num; } And the declarative approach using .reduce(). const sumAge = (collection) => collection.reduce((sum, person) => { return sum + person.age; }, 0); We can even use .reduce() to create our own implementation of .map() and .filter() . const map = (collection, fn) => { return collection.reduce((acc, item) => { return acc.concat(fn(item)); }, []); } const filter = (collection, fn) => { return collection.reduce((acc, item) => { if (fn(item)) { return acc.concat(item); } return acc; }, []); } This might be hard to understand at first. But what .reduce() basically does is start with a collection and a variable with an initial value. You then iterate over the collection and append (or add) the values to the variable.

    Combining map, filter and reduce

    These functions can be used together! This makes it easy to create reusable functions and reduce the amount of code that is required to write certain functionality. So we talked about using .filter() to filter out the people that are equal or below the age of 18. .map() to add the coffeeLover property, and .reduce() to finally create a sum of the age of everyone combined. Lets write some code that actually combines these three steps. const people = [ { name: ‘John Doe’, age: 16 }, { name: ‘Thomas Calls’, age: 19 }, { name: ‘Liam Smith’, age: 20 }, { name: ‘Jessy Pinkman’, age: 18 },]; const coffeeLovers = [‘John Doe’, ‘Liam Smith’, ‘Jessy Pinkman’]; const ageAbove18 = (person) => person.age >= 18;const addCoffeeLoverProperty = (person) => { person.coffeeLover = coffeeLovers.includes(person.name); return person;} const ageReducer = (sum, person) => { return sum + person.age;}, 0); const coffeeLoversAbove18 = people .filter(ageAbove18) .map(addCoffeeLoverProperty); const totalAgeOfCoffeeLoversAbove18 = coffeeLoversAbove18 .reduce(ageReducer); const totalAge = people .reduce(ageReducer); If you do it the imperative way, you will end up writing a lot of repeating code. The mindset of creating functions with .map() ,.reduce() and .filter() will improve the quality of the code you’ll write. But it also adds a lot of readability. You don’t have to think about what’s going on inside a function. It’s easy to understand. Higher Order Functions (Composing Software) A Guide To The Reduce Method In Javascript if-else conditon in arrow function Flattening an array of arrays var data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; var flat = data.reduce((total, amount) => total.concat(amount)) flat // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] if-else conditon in arrow function function(a){ if(a < 10){ return 'valid'; }else{ return 'invalid'; } } The equivalent in an arrow function using a ternary is: a => (a < 10) ? 'valid' : 'invalid' the body of an arrow function without braces can only be a single expression, so if statements are not allowed. Statements are allowed in arrow functions with braces though, like this: const func = () => { if (...) ... } for a single 'if' condition, may use a shortcut syntax. Imagine you need to execute a doThis() function only if a > 10 : a => a > 10 && doThis()

    高阶函数


    如何理解高阶函数高阶函数的优势常用的高阶函数:让数组操作更简单自定义高阶函数结束
    高阶函数就是可以把其他函数当作参数传进去,或者把函数作为结果返回的函数。 高阶函数可以帮助我们写出更加模块化、可重用的代码。 举个例子,如果你经常需要在代码里做一些重复性的操作,比如对数组里的每个元素做某种处理,有了高阶函数,我们可以把这些操作提取出来,写成一个通用的函数,然后在需要的时候直接调用。 这样一来,不但减少了代码的重复,还让代码逻辑更加清晰。

    如何理解高阶函数

    假设我们要制作一份饮料菜单,菜单上的饮料可以是各种不同的类型,比如果汁、咖啡、奶茶等。 我们先定义两个制作饮料的函数: function makeJuice(size) { return `A cup of ${size} juice`; } function makeCoffee(size) { return `A cup of ${size} coffee`; } 然后,我们定义一个高阶函数 orderDrink,它接受一个制作饮料的函数 makeDrink 和一个大小参数 size: function orderDrink(makeDrink, size) { return makeDrink(size); } 这样,我们就可以通过传递不同的制作饮料的函数和大小参数,来制作不同的饮料: console.log(orderDrink(makeJuice, 'large')); // 输出: A cup of large juice console.log(orderDrink(makeCoffee, 'small')); // 输出: A cup of small coffee 在这个例子中,orderDrink 是一个高阶函数,它接受一个函数 makeDrink 和一个参数 size。 orderDrink 调用 makeDrink,并传入 size 作为参数,然后返回制作好的饮料。 我们定义了两个简单的函数 makeJuice 和 makeCoffee,分别制作果汁和咖啡。 通过将这两个函数作为参数传递给 orderDrink,我们可以制作不同大小的饮料,而无需修改 orderDrink 函数本身。 这个例子展示了高阶函数的一个重要特性:代码复用性和可扩展性。 我们只需要编写一次 orderDrink 函数,就可以通过传递不同的制作饮料的函数,实现多种不同的饮料制作方法。 这在实际开发中非常有用,特别是当我们需要对某一类操作进行抽象和泛化时。

    高阶函数的优势

    抽象化:让代码更简洁 高阶函数可以帮助你将常见的模式和行为抽象出来,使代码更具可读性和简洁性。 比如,我们常常需要对数组中的每个元素进行操作,如果每次都单独写一遍代码,会非常繁琐。 通过高阶函数,我们可以把这些操作抽象成一个通用的函数,简化代码。 复用性:打造可复用的积木 通过将功能封装到高阶函数中,你可以创建出可复用的代码块。 这样一来,不同的项目中你都可以轻松地使用这些函数,而不需要重复造轮子。 例如,一个通用的排序函数,可以在不同的数据处理中复用,只需传入不同的排序逻辑。 模块化:分而治之 高阶函数提倡模块化编程方法,将复杂的任务分解成更小、更专注的函数。 这样不仅使代码更易于理解和维护,还能提高开发效率。 每个小函数只关注自己的任务,减少了相互之间的依赖。 灵活性:自由定制 高阶函数让你可以通过传递不同的回调函数,自由定制函数的行为,从而实现更大的灵活性和适应性。 比如,你可以通过传入不同的回调函数,动态改变数据处理的方式,使代码更加适应不同的需求。

    常用的高阶函数:让数组操作更简单

    在 JavaScript 中,有很多内置的高阶函数,特别适用于数组的操作和转换。 Array.prototype.map map 函数通过对原数组中的每个元素调用提供的回调函数,创建一个新数组。 例如,我们有一个包含学生成绩的数组,想要将每个成绩提升10分: const grades = [70, 85, 90, 78, 92]; const improvedGrades = grades.map(grade => grade + 10); console.log(improvedGrades); // 输出: [80, 95, 100, 88, 102] 在这个例子中,map 被用来创建一个新数组 improvedGrades,通过对 grades 数组中的每个成绩加10分。 回调函数 grade => grade + 10 被应用到每个元素上,结果存储在新数组的对应位置。 Array.prototype.filter filter 函数通过检查数组中的每个元素,创建一个新数组,包含所有通过回调函数测试的元素。 例如,我们有一个年龄数组,想要筛选出所有成年人(18岁及以上): const ages = [12, 18, 25, 16, 30]; const adults = ages.filter(age => age >= 18); console.log(adults); // 输出: [18, 25, 30] 在这个例子中,filter 被用来创建一个新数组 adults,通过对 ages 数组中的每个年龄进行成年检查。 回调函数 age => age >= 18 被应用到每个元素上,只有通过检查的元素才会被包含在新数组中。 Array.prototype.reduce reduce 函数通过对数组中的每个元素执行一个提供的回调函数,将数组缩减为单个值。 例如,我们有一个商品价格数组,想要计算所有商品的总价: const prices = [100, 200, 300, 400, 500]; const totalPrice = prices.reduce((total, price) => total + price, 0); console.log(totalPrice); // 输出: 1500 在这个例子中,reduce 被用来将 prices 数组缩减为一个单个值 totalPrice,通过对每个元素执行累加操作。 回调函数 (total, price) => total + price 被应用到每个元素上,total 是累加器,price 是当前元素,初始值为 0。

    自定义高阶函数

    除了使用内置的高阶函数,你还可以创建自己的高阶函数来封装特定的行为或模式。 这样可以让你的代码更具灵活性和可读性。 我们通过一个简单的例子来展示如何创建自定义高阶函数。 自定义高阶函数示例 假设我们有一个数字数组,希望对数组中的每个数字进行某种转换操作。 我们可以创建一个高阶函数 transformArray 来实现这个需求。 // 定义一个自定义高阶函数 transformArray function transformArray(arr, transformFunc) { const transformedArray = []; // 创建一个空数组用于存储转换后的结果 for (let i = 0; i < arr.length; i++) { // 遍历输入数组的每个元素 transformedArray.push(transformFunc(arr[i])); // 将转换后的元素添加到新数组中 } return transformedArray; // 返回转换后的新数组 } // 定义一个数字数组 const numbers = [1, 2, 3, 4, 5]; // 使用 transformArray 函数将每个数字乘以 2 const doubledNumbers = transformArray(numbers, num => num * 2); // 输出转换后的数组 console.log(doubledNumbers); // 输出: [2, 4, 6, 8, 10] 在这个例子中,transformArray 是一个高阶函数,它接受一个数组 arr 和一个转换函数 transformFunc 作为参数。 函数内部创建了一个新数组 transformedArray,通过对输入数组 arr 的每个元素应用 transformFunc,将转换后的结果存储在新数组中,最后返回新数组。 我们通过调用 transformArray,传入一个数字数组 numbers 和一个将数字乘以 2 的转换函数 num => num * 2,得到一个新的数组 doubledNumbers,其中包含了每个原始数字的两倍。

    结束

    高阶函数是JavaScript中一个非常强大的特性,它让开发者能够编写更加模块化、可复用且富有表现力的代码。 通过将函数视为一等公民,高阶函数允许我们抽象出常见的模式,创建可复用的构建块,并通过回调函数定制行为。 JavaScript 提供了多个内置的高阶函数,比如 map、filter 和 reduce,这些都是数组操作和转换中的宝贵工具。 此外,你还可以创建自己的高阶函数,封装特定的行为和模式,使代码更具可读性和可维护性。

    Template Literals

    JavaScript Template Literals
    字符串插值
    多行文本
    嵌套模板
    带标签的模板
    Description
    Multi-line strings
    String interpolation
    Nesting templates
    Tagged templates
    Raw strings
    Tagged templates and escape sequences
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

    字符串插值

    JavaScript 中使用反引号 ` 包裹的字符串叫模板字符串(template literals)。 人们常用它拼接变量和字符串,即所谓的字符串插值(string interpolation)。 在使用字符串插值时,使用 ${} 包裹变量或表达式,它是变量的占位符。

    多行文本

    模板字符串支持多行文本(multi-line strings)。

    嵌套模板

    它还支持嵌套模板(nesting templates)。 即在一个模板字符串的变量内,使用另一个模板字符串。

    带标签的模板

    它还有另外一个略显高级的用法:带标签的模板(tagged templates),有时也叫标签函数(tag function),指的都是一回事。 在带标签的模板中,标签其实是一个函数,它可以处理模板字符串的内容。 该函数的第一个参数是字符串数组,包括模板字符串的所有静态字符字面量,后面的不定参数,按照先后顺序分别对应 ${} 对应的变量。 函数返回值会当作模板字符串变量的最终值。 只要你想,返回值可以和入参完全无关。 标签函数属于可变参数函数(variadic functions),在 JavaScript 中可以使用三个点 ... 剩余参数(rest parameters)语法,将所有的变量收集到一个数组。 标签函数的返回值可以是任意类型,不一定是字符串。 除了普通变量,带标签模板的“标签”还可以是表达式,只要它的操作符优先级大于 16 即可。 满足条件的表达式有属性访问 x.y、函数调用 x(y)、创建对象 new x(y),甚至另一个标签模板字面量 带标签模板的实际应用有哪些? 如果你接触过谷歌的 zx 命令行工具,或者谷歌的 Lit 框架(谷歌真喜欢用它),就会见到它的实际用法。 下图中的 $ 和 html 就是标签函数。 Template literals are literals delimited with backtick (`) characters, allowing for multi-line strings, string interpolation with embedded expressions, and special constructs called tagged templates. Template literals are sometimes informally called template strings, because they are used most commonly for string interpolation (to create strings by doing substitution of placeholders). However, a tagged template literal may not result in a string; it can be used with a custom tag function to perform whatever operations you want on the different parts of the template literal.

    Syntax

    `string text` `string text line 1 string text line 2` `string text ${expression} string text` tagFunction`string text ${expression} string text`

    Parameters

    string text The string text that will become part of the template literal. Almost all characters are allowed literally, including line breaks and other whitespace characters. However, invalid escape sequences will cause a syntax error, unless a tag function is used. expression An expression to be inserted in the current position, whose value is converted to a string or passed to tagFunction. tagFunction If specified, it will be called with the template strings array and substitution expressions, and the return value becomes the value of the template literal. See tagged templates.

    Description

    Template literals are enclosed by backtick (`) characters instead of double or single quotes. Along with having normal strings, template literals can also contain other parts called placeholders, which are embedded expressions delimited by a dollar sign and curly braces: ${expression}. The strings and placeholders get passed to a function — either a default function, or a function you supply. The default function(when you don't supply your own) just performs string interpolation to do substitution of the placeholders and then concatenate the parts into a single string. To supply a function of your own, precede the template literal with a function name; the result is called a tagged template. In that case, the template literal is passed to your tag function, where you can then perform whatever operations you want on the different parts of the template literal. To escape a backtick in a template literal, put a backslash (\) before the backtick. `\`` === "`"; // true Dollar signs can be escaped as well to prevent interpolation. `\${1}` === "${1}"; // true

    Multi-line strings

    Any newline characters inserted in the source are part of the template literal. Using normal strings, you would have to use the following syntax in order to get multi-line strings: console.log("string text line 1\n" + "string text line 2"); // "string text line 1 // string text line 2" Using template literals, you can do the same with this: console.log(`string text line 1 string text line 2`); // "string text line 1 // string text line 2" Like normal string literals, you can write a single-line string across multiple lines for source code readability, by escaping the newline with a backslash (\): console.log(`string text line 1 \ string text line 2`); // "string text line 1 string text line 2"

    String interpolation

    Without template literals, when you want to combine output from expressions with strings, you'd concatenate them using the addition operator +: const a = 5; const b = 10; console.log("Fifteen is " + (a + b) + " and\nnot " + (2 * a + b) + "."); // "Fifteen is 15 and // not 20." That can be hard to read – especially when you have multiple expressions. With template literals, you can avoid the concatenation operator — and improve the readability of your code — by using placeholders of the form ${expression} to perform substitutions for embedded expressions: const a = 5; const b = 10; console.log(`Fifteen is ${a + b} and not ${2 * a + b}.`); // "Fifteen is 15 and // not 20." Note that there's a mild difference between the two syntaxes. Template literals coerce their expressions directly to strings, while addition coerces its operands to primitives first. For more information, see the reference page for the + operator.

    Nesting templates

    In certain cases, nesting a template is the easiest (and perhaps more readable) way to have configurable strings. Within a backtick-delimited template, it is simple to allow inner backticks by using them inside an ${expression} placeholder within the template. For example, without template literals, if you wanted to return a certain value based on a particular condition, you could do something like the following: let classes = "header"; classes += isLargeScreen() ? "" : item.isCollapsed ? " icon-expander" : " icon-collapser"; With a template literal but without nesting, you could do this: const classes = `header ${ isLargeScreen() ? "" : item.isCollapsed ? "icon-expander" : "icon-collapser" }`; With nesting of template literals, you can do this: const classes = `header ${ isLargeScreen() ? "" : `icon-${item.isCollapsed ? "expander" : "collapser"}` }`;

    Tagged templates

    A more advanced form of template literals are tagged templates. Tags allow you to parse template literals with a function. The first argument of a tag function contains an array of string values. The remaining arguments are related to the expressions. The tag function can then perform whatever operations on these arguments you wish, and return the manipulated string. (Alternatively, it can return something completely different, as described in one of the following examples.) The name of the function used for the tag can be whatever you want. const person = "Mike"; const age = 28; function myTag(strings, personExp, ageExp) { const str0 = strings[0]; // "That " const str1 = strings[1]; // " is a " const str2 = strings[2]; // "." const ageStr = ageExp < 100 ? "youngster" : "centenarian"; // We can even return a string built using a template literal return `${str0}${personExp}${str1}${ageStr}${str2}`; } const output = myTag`That ${person} is a ${age}.`; console.log(output); // That Mike is a youngster. The tag does not have to be a plain identifier. You can use any expression with precedence greater than 16, which includes property access, function call, new expression, or even another tagged template literal. console.log`Hello`; // [ 'Hello' ] console.log.bind(1, 2)`Hello`; // 2 [ 'Hello' ] new Function("console.log(arguments)")`Hello`; // [Arguments] { '0': [ 'Hello' ] } function recursive(strings, ...values) { console.log(strings, values); return recursive; } recursive`Hello``World`; // [ 'Hello' ] [] // [ 'World' ] [] While technically permitted by the syntax, untagged template literals are strings and will throw a TypeError when chained. console.log(`Hello``World`); // TypeError: "Hello" is not a function The only exception is optional chaining, which will throw a syntax error. console.log?.`Hello`; // SyntaxError: Invalid tagged template on optional chain console?.log`Hello`; // SyntaxError: Invalid tagged template on optional chain Note that these two expressions are still parsable. This means they would not be subject to automatic semicolon insertion, which will only insert semicolons to fix code that's otherwise unparsable. // Still a syntax error const a = console?.log `Hello` Tag functions don't even need to return a string! function template(strings, ...keys) { return (...values) => { const dict = values[values.length - 1] || {}; const result = [strings[0]]; keys.forEach((key, i) => { const value = Number.isInteger(key) ? values[key] : dict[key]; result.push(value, strings[i + 1]); }); return result.join(""); }; } const t1Closure = template`${0}${1}${0}!`; // const t1Closure = template(["","","","!"],0,1,0); t1Closure("Y", "A"); // "YAY!" const t2Closure = template`${0} ${"foo"}!`; // const t2Closure = template([""," ","!"],0,"foo"); t2Closure("Hello", { foo: "World" }); // "Hello World!" const t3Closure = template`I'm ${"name"}. I'm almost ${"age"} years old.`; // const t3Closure = template(["I'm ", ". I'm almost ", " years old."], "name", "age"); t3Closure("foo", { name: "MDN", age: 30 }); // "I'm MDN. I'm almost 30 years old." t3Closure({ name: "MDN", age: 30 }); // "I'm MDN. I'm almost 30 years old." The first argument received by the tag function is an array of strings. For any template literal, its length is equal to the number of substitutions (occurrences of ${…}) plus one, and is therefore always non-empty. For any particular tagged template literal expression, the tag function will always be called with the exact same literal array, no matter how many times the literal is evaluated. const callHistory = []; function tag(strings, ...values) { callHistory.push(strings); // Return a freshly made object return {}; } function evaluateLiteral() { return tag`Hello, ${"world"}!`; } console.log(evaluateLiteral() === evaluateLiteral()); // false; each time `tag` is called, it returns a new object console.log(callHistory[0] === callHistory[1]); // true; all evaluations of the same tagged literal would pass in the same strings array This allows the tag to cache the result based on the identity of its first argument. To further ensure the array value's stability, the first argument and its raw property are both frozen, so you can't mutate them in any way.

    Raw strings

    The special raw property, available on the first argument to the tag function, allows you to access the raw strings as they were entered, without processing escape sequences. function tag(strings) { console.log(strings.raw[0]); } tag`string text line 1 \n string text line 2`; // Logs "string text line 1 \n string text line 2" , // including the two characters '\' and 'n' In addition, the String.raw() method exists to create raw strings just like the default template function and string concatenation would create. const str = String.raw`Hi\n${2 + 3}!`; // "Hi\\n5!" str.length; // 6 Array.from(str).join(","); // "H,i,\\,n,5,!" String.raw functions like an "identity" tag if the literal doesn't contain any escape sequences. In case you want an actual identity tag that always works as if the literal is untagged, you can make a custom function that passes the "cooked" (i.e. escape sequences are processed) literal array to String.raw, pretending they are raw strings. const identity = (strings, ...values) => String.raw({ raw: strings }, ...values); console.log(identity`Hi\n${2 + 3}!`); // Hi // 5! This is useful for many tools which give special treatment to literals tagged by a particular name. const html = (strings, ...values) => String.raw({ raw: strings }, ...values); // Some formatters will format this literal's content as HTML const doc = html`<!doctype html> <html lang="en-US"> <head> <title>Hello</title> </head> <body> <h1>Hello world!</h1> </body> </html>`;

    Tagged templates and escape sequences

    In normal template literals, the escape sequences in string literals are all allowed. Any other non-well-formed escape sequence is a syntax error. This includes: \ followed by any decimal digit other than 0, or \0 followed by a decimal digit; for example \9 and \07 (which is a deprecated syntax) \x followed by fewer than two hex digits (including none); for example \xz \u not followed by { and followed by fewer than four hex digits (including none); for example \uz \u{} enclosing an invalid Unicode code point — it contains a non-hex digit, or its value is greater than 10FFFF; for example \u{110000} and \u{z} Note: \ followed by other characters, while they may be useless since nothing is escaped, are not syntax errors. However, this is problematic for tagged templates, which, in addition to the "cooked" literal, also have access to the raw literals (escape sequences are preserved as-is). Tagged templates enable the embedding of arbitrary string content, where escape sequences may follow a different syntax. Consider for a simple example where we embed LaTeX source text in JavaScript via String.raw. We want to still be able to use LaTeX macros that start with u or x without following JavaScript syntax restrictions. Therefore, the syntax restriction of well-formed escape sequences is removed from tagged templates. The example below uses MathJax to render LaTeX in one element: const node = document.getElementById("formula"); MathJax.typesetClear([node]); // Throws in older ECMAScript versions (ES2016 and earlier) // SyntaxError: malformed Unicode character escape sequence node.textContent = String.raw`$\underline{u}$`; MathJax.typesetPromise([node]); However, illegal escape sequences must still be represented in the "cooked" representation. They will show up as undefined element in the "cooked" array: function log(str) { console.log("Cooked:", str[0]); console.log("Raw:", str.raw[0]); } log`\unicode`; // Cooked: undefined // Raw: \unicode Note that the escape-sequence restriction is only dropped from tagged templates, but not from untagged template literals: const bad = `bad escape sequence: \unicode`;

    console.log variable using ES6 back tick

    console.log("story " + name + " story"); When using ES6: let name = prompt("what is your name?"); console.log(`story ${name} story`); Template literals can be used to represent multi-line strings and may use "interpolation" to insert variables: var a = 123, str = `--- a is: ${a} ---`; console.log(str); Output: --- a is: 123 --- What is more important, they can contain not just a variable name, but any JavaScript expression: var a = 3, b = 3.1415; console.log(`PI is nearly ${Math.max(a, b)}`);

    Scroll Load Dynamic Content



    Infinite Scroll

    Jquery Infinite Scrolling . Infinite Scroll Methods . Infinite Scroll.js的使用
    infinite scroll.com . javascript infinite scroll
    jQuery load more data on scroll
    Load more results after scroll to end of list
    Automatic Load More Plugin For jQuery

    Use children() and each() to loop

    Use children() and each(), you can optionally pass a selector to children children() is a loop in itself. $('div').children('input').each(function() { alert(this.value); });

    $(this) to loop

    Examples of jQuery Selectors $("*") Selects all elements $(this) Selects the current HTML element $("p.intro") $("p:first") $("ul li:first") $("ul li:first-child") $("[href]") Selects all elements with an href attribute $("a[target='_blank']")equal to "_blank" $("a[target!='_blank']") NOT equal to "_blank" $(":button") $("tr:even") $("tr:odd") $( "li.item-ii" ).find( "li" ).css( "background-color", "red" ); $( "p" ).find( "span" ).css( "color", "red" ); $('.pizza-maker').find('.cheese').find('a').addClass('cheese-style') .children('.cheese') was called on and stopped there. jquery $(this)id jquery $(this).val() jquery $(this).find jquery $(this).next jquery $(this).attr jquery $(this).index jquery $(this).text() jquery $(this).children jquery $(this).attr("id") jquery $(this).css jquery $(this).on() jquery $(this).is() jquery $(this).get() jquery $(this).parents() .children() var kids = $( event.target ).children(); var len = kids.addClass( "hilite" ).length; $( "#results span:first" ).text( len ); $( "#results span:last" ).text( event.target. .not() .index() $( "div" ).click(function() { var index = $( "div" ).index( this ); $( "span" ).text( "That was div index #" + index ); :first-child Selector .filter() $( "li" ) .filter(function( index ) { return $( "strong", this ).length === 1; }) .css( "background-color", "red" ); .siblings() :visible Selector .val() "select#foo" ).val(); $( "input[type=checkbox][name=bar]:checked" ).val(); .one() var index = $( "div" ).index( this ); $( this ).css({borderStyle: "inset",cursor: "auto"}); $( "p" ).text( "Div at index #" + index + " clicked." + " That's " + (++n) + " total ... .prev() $(this.htmltable + ' th[data-field]').each(function(i, col){ this.dbcolumns.push( $(col).attr('data-field') ); }.bind(this)); $(".myCheckboxes").change(function(){ if(this.checked){alert("checked");} }); $(".class").each(function(){ var HTMLElement = this; //the current HTML element is passed to the jQuery constructor //the jQuery API is exposed here (such as .html() and .append()) var jQueryObject = $(this); }); $('.somediv').click(function(){ $(this).addClass('newDiv'); }); $('.multiple-elements').each( function(index, element) { $(this).css('background-color', $(this).data('bgcol')); } ); <a href="#" onclick="$(this).css('display', 'none')">Hide me!

    $(this) nested loop

    $('li').each(function(){ var $this = $(this); $this.children("li").each(function(){ $this; // parent li this; // child li }); }); $('li').children("li").each(function(){ var $this = $(this); }); $('.pizza-maker').find('.cheese').find('a').addClass('cheese-style') .children('.cheese') was called on and stopped there.

    todo-list-indexeddb

    todo-list-indexeddb

    stars

    stars

    Learn Node.js

    Learn Node.js - Full Tutorial for Beginners

    scroll-behavior

    html { scroll-behavior: smooth;} $(document).ready(function(){ $('body,html').animate({scrollTop: 156}, 800); }); 156 - position scroll to (px), from top of page. 800 - scroll duration (ms) scroll to bottom $(document).ready(function(){ $('body,html').animate({scrollTop:$(document).height()}, 800000); }); scroll to a div $(document).ready(function(){ $('body,html').animate({scrollTop: $('#toc').get(0).scrollHeight}, 630000); }); $('html, body').animate({ scrollTop: $('idName').offset().top-100 }, timelength); jQuery different scroll speeds

    Quiz Online Test

    Many JavaScript Samples Quiz Online Test

    Date Time Countdown Tutorial

    Date Time Countdown Tutorial

    Client-side web scraping

    JavaScript Client-side web scraping

    keycodes

    keycodes

    higher order function

    A higher order function is a function that takes a function as an argument, or returns a function. Higher order function is in contrast to first order functions, which don’t take a function as an argument or return a function as output. examples of .map() and .filter(). Both of them take a function as an argument. They're both higher order functions. Example 1# Let’s say we have an array of numbers and we want to create a new array which contains double of each value of the first array. Let’s see how we can solve the problem with and without Higher-Order Function. Without Higher-order function const arr1 = [1, 2, 3]; const arr2 = []; for(let i = 0; i < arr1.length; i++) { arr2.push(arr1[i] * 2); } // prints [ 2, 4, 6 ] console.log(arr2); With Higher-order function map const arr1 = [1, 2, 3]; const arr2 = arr1.map(function(item) { return item * 2; }); console.log(arr2); We can make this even shorter using the arrow function syntax: const arr1 = [1, 2, 3]; const arr2 = arr1.map(item => item * 2); console.log(arr2); Example 2# Let’s say we have an array containing the birth year of different persons and we want to create an array that contains their ages. For example: Without Higher-order function const birthYear = [1975, 1997, 2002, 1995, 1985]; const ages = []; for(let i = 0; i < birthYear.length; i++) { let age = 2018 - birthYear[i]; ages.push(age); } // prints [ 43, 21, 16, 23, 33 ] console.log(ages); With Higher-order function map const birthYear = [1975, 1997, 2002, 1995, 1985]; const ages = birthYear.map(year => 2018 - year); // prints [ 43, 21, 16, 23, 33 ] console.log(ages);
    Example var sum = function(n1, n2) {//This is just a function return n1 + n2; }; sum(1,2);//3 function makeSumN(n) {//This is a higher-order function return function(p) { sum(n, p) } } var sum1 = makeSumN(1); sum1(2); //3 function makeMoreThanSum(f) {//This is a higher-order function return function(n1, n2) { sum(f(n1), n2) } } var sumSquareOfFirst = makeMoreThanSum(function(n){ return n*n; }); sumSquareOfFirst(2,1);//5 Example function createMultiplier(multiplier){return function(x){ return x * multiplier} } let doubleme = createMultiplier(2) let tripleme = createMultiplier(3) let quadrupleme = createMultiplier(4) console.log(doubleme(5)) console.log(tripleme(3)) console.log(quadrupleme(7))

    蒙版

    蒙版弹幕 Barrage UI 纯客户端 实时 蒙版 弹幕

    run HTA

    CMDTail='\");close();' LAmtNotice="BigVol!" # popup message LF = "\\n" onecode = '0030' codename = "abcde" curPrice = "31.5" AlertMsg=paste0( 'mshta javascript:alert(<meta http-equiv="x-ua-compatible" content="ie=edge" />\"',"Alarm!!",LF, '<br><br><br>', onecode,LF ,codename, LF,"Price ",curPrice, LF, format(Sys.time(), "%H:%M:%OS"),LF, CMDTail) system(AlertMsg, invisible=T, wait=F) Usually, HTML5 doesn't work in HTA files because they are run by mshta.exe which acts like IE7 and HTML5 isn't supported in earlier versions of IE than IE9. But if you add <meta http-equiv="x-ua-compatible" content="ie=edge" /> in the head of the HTA, the HTA will act like the version of IE installed on the computer, so if the computer has IE9 or later and you add that tag, it will work. The problem with this is that if you upgrade the HTA, the <hta:application/> tag won't have any effect so you will lose all effects like icons, window properties, etc. For this reason, I prefer to not upgrade the HTA and to use workarounds instead of HTML5. In HTA, to get the code to properly work, you must include the tag <meta http-equiv="x-ua-compatible" content="ie=edge" /> or <meta http-equiv="x-ua-compatible" content="ie=9">to get the JavaScript and HTML 5 to work completely. You may add <HTA:APPLICATION APPLICATIONNAME="HTA" ID="HTA" VERSION="1.0" MAXIMIZEBUTTON="no"/> Hacking around HTA files HTML5 work in a .hta file HTML Applications

    九种跨域方式实现原理

    九种跨域方式实现原理

    parse Excel file

    parse Excel file in Javascript/HTML5
    Excel to JSON javascript code
    Parse and Read Excel Files (xls/xlsx) With JavaScript
    SheetJS Tutorial – Convert Excel to HTML Table

    Multiple setIntervals running at once

    In JS you can't. To have multiple functions in the same program execute at the same time you need multi-threading and some deep timing and thread handling skills. JavaScript is single threaded. Can use html5 web worker or try using setTimeout recursively. Create multiple functions following this example: var interval = setTimeout(appendDateToBody, 5000); function appendDateToBody() { document.body.appendChild( document.createTextNode(new Date() + " ")); interval = setTimeout(appendDateToBody, 5000); }

    add the crossorigin tag to a dynamically loaded script

    add the crossorigin tag to a dynamically loaded script

    link in alert boxes javascript

    link in alert boxes javascript alert function can only display text // use window.confirm instead of alert if (window.confirm('click "ok" to redirect. Cancel to stay ')) { window.location.href='http://www.google.com'; }; if (window.confirm('Ok to Confirm, Cancel to Stay here')) { window.open('http://www.google.com', '_blank'); };

    Formatting numbers with commas

    var number = 12345.543; number.toLocaleString();"12,345.543"

    To create a global variable

    To create a global variable, just omit 'var' from the statement. When you omit 'var', you're actually creating the variable in the window namespace. So, zz = 1 is actually window.zz = 1 A global variable has global scope which means it can be defined anywhere in your JavaScript code. Variables declared within a JavaScript function, become LOCAL to the function. A variable declared outside a function, becomes GLOBAL.

    jQuery $.ajax()

    Some of jQuery's most used Ajax shorthand methods: $.get(), $.post(), and $.load(). They are convenient methods for making Ajax requests in a few lines of code.
    Sometimes, we need more control over the Ajax calls we want to make. For example, we want to specify what should happen in case an Ajax call fails or we need to perform an Ajax request but its result is only needed if retrieved within a certain amount of time. In such situations, we can rely on another function provided by jQuery, called $.ajax(), that is the topic of this tutorial.

    The $.ajax() Function

    The jQuery function is used to perform an asynchronous HTTP request. It was added to the library a long time ago, existing since version 1.0. The $.ajax() function is what every function discussed in the previously mentioned article calls behind the scene using a preset configuration. The signatures of this function are shown below:
    $.ajax(url[, options]) $.ajax([options]) The url parameter is a string containing the URL you want to reach with the Ajax call, while options is an object literal containing the configuration for the Ajax request.
    In its first form, this function performs an Ajax request using the url parameter and the options specified in options. In the second form, the URL is specified in the options parameter, or can be omitted in which case the request is made to the current page.
    The list of the options accepted by this function, described in the next section, is very long. So, I'll keep their description short. In case you want to study in-depth their meaning, you can refer to .

    The option Parameter

    There are a lot of different options you can specify to bend $.ajax() to your need. In the list below you can find their names and their description sorted in alphabetic order:
    accepts: The content type sent in the request header that tells the server what kind of response it will accept in return
    async: Set this options to false to perform a synchronous request
    beforeSend: A pre-request callback function that can be used to modify the jqXHR object before it is sent
    cache: Set this options to false to force requested pages not to be cached by the browser
    complete: A function to be called when the request finishes (after success and error callbacks are executed)
    contents: An object that determines how the library will parse the response
    contentType: The content type of the data sent to the server
    context: An object to use as the context (this) of all Ajax-related callbacks
    converters: An object containing dataType-to-dataType converters
    crossDomain: Set this property to true to force a cross-domain request (such as JSONP) on the same domain
    data: The data to send to the server when performing the Ajax request
    dataFilter: A function to be used to handle the raw response data of XMLHttpRequest
    dataType: The type of data expected back from the server
    error: A function to be called if the request fails
    global: Whether to trigger global Ajax event handlers for this request
    headers: An object of additional headers to send to the server
    ifModified: Set this option to true if you want to force the request to be successful only if the response has changed since the last request
    isLocal: Set this option to true if you want to force jQuery to recognize the current environment as "local"
    jsonp: A string to override the callback function name in a JSONP request
    jsonpCallback: Specifies the callback function name for a JSONP request
    mimeType: A string that specifies the mime type to override the XHR mime type
    password: A password to be used with XMLHttpRequest in response to an HTTP access authentication request
    processData : Set this option to false if you don't want that the data passed in to the data option (if not a string already) will be processed and transformed into a query string
    scriptCharset: Sets the charset attribute on the script tag used in the request but only applies when the "script" transport is used
    statusCode: An object of numeric HTTP codes and functions to be called when the response has the corresponding code
    success: A function to be called if the request succeeds
    timeout: A number that specifies a timeout (in milliseconds) for the request
    traditional: Set this to true if you wish to use the traditional style of param serialization
    type: The type of request to make, which can be either "POST" or "GET"
    url: A string containing the URL to which the request is sent
    username: A username to be used with XMLHttpRequest in response to an HTTP access authentication request
    xhr: A callback for creating the XMLHttpRequest object
    xhrFields: An object to set on the native XHR object
    That was pretty long, isn't it? Well, as developers you probably have stopped reading this list at the fifth or sixth element I guess, but that's fine. The next section will be more exciting because we'll put the $.ajax() function and some of these options into action.

    $.ajax

    No 'Access-Control-Allow-Origin' header is present on the requested resource. make a http request using CORS with jquery: ============ $.ajax({ url: theurl, // This is the important part xhrFields: {withCredentials: true}, // This is the important part data: data, success: function(response) { // handle the response }, error: function(xhr, status) { // handle errors } }); ============ $.ajax({ url: "http://localhost:8079/students/add/", type: "POST", crossDomain: true, data: JSON.stringify(somejson), dataType: "json", success: function(response) { var resp = JSON.parse(response) alert(resp.status); }, error: function(xhr, status) { alert("error"); } }); ============ var settings = { 'cache': false, // 'dataType': "jsonp", "async": true, "crossDomain": true, "url": theurl, "method": "GET", "headers": { "accept": "application/json", "Access-Control-Allow-Origin":"*" } } $.ajax(settings).done(function(response) {console.log(response);}); $.ajax(theurl, {success: function(data) {$('body').append(data);} }); ============ var bodycontent = $('body'); $.ajax({ url: theurl, xhrFields: {withCredentials: true}, crossDomain: true, success: function(rawData){ body.append(rawData);; }}); ============ 使用 JSONP 跨站請求
    Creating a Dynamic Script Tag and Request With a Callback Function
    <script> function clickButton() { var s = document.createElement("script"); s.src = "demo_jsonp.php"; document.body.appendChild(s); } function clickButton() { var s = document.createElement("script"); s.src = "jsonp_demo_db.php?callback=myDisplayFunction"; document.body.appendChild(s); } 透過 jsonp 的方法所傳送的 URL 當中,結尾都會帶一個問號 (?), 這個問號會在取得 server 回傳值的時候,自動轉換成 call function 的 function name,而如果是一個匿名函式,則會轉換成一個帶有 time stamp 的函式名稱。 當傳輸完成後,client 會自動執行 Server 回傳的 callback function,取得結果。 function foo(data) { // do stuff with JSON } var script = document.createElement('script'); script.src = '//example.com/path/to/jsonp?callback=foo' document.getElementsByTagName('head')[0].appendChild(script); // or document.head.appendChild(script) in modern browsers

    Minify Javascript

    JSCompress Minify Javascript Or Css Code how to minify javascript code The JavaScript Minifier JSMin jsmin <fulljslint.js >jslint.js "(c)2002 Douglas Crockford"

    createElement("INPUT")

    function myFunction() { var x = document.createElement("INPUT"); x.setAttribute("type", "radio"); document.body.appendChild(x); }

    conditional operator ? :

    conditional operator https://stackoverflow.com/questions/6259982/how-do-you-use-the-conditional-operator-in-javascript ? : (conditional) operator in JavaScript The conditional operator is the only JavaScript operator that takes three operands. This operator is frequently used as a shortcut for the if statement. JavaScript Demo: Expressions - Conditional operator function getFee(isMember) { return (isMember ? "$2.00" : "$10.00"); } function zeroFill(num) { return num < 10 ? '0' + num : num; }

    jQuery on() Method

    $(selector).on(event,childSelector,data,function,map) Example Attach a click event to the p element: $("p").on("click", function(){ alert("The paragraph was clicked."); }); $( "#dataTable tbody tr" ).on( "click", function() { console.log( $( this ).text() ); }); event Required. Specifies one or more event(s) or namespaces to attach to the selected elements.
    Multiple event values are separated by space. Must be a valid event childSelector Optional. Specifies that the event handler should only be attached to the specified child elements (and not the selector itself, like the deprecated delegate() method). data Optional. Specifies additional data to pass along to the function function Required. Specifies the function to run when the event occurs map Specifies an event map ({event:function, event:function, ...}) containing one or more event to attach to the selected elements, and functions to run when the events occur ===========================

    Looping through objects in JavaScript

    Once in a while, you may need to loop through Objects in JavaScript. The only way to do so before ES6 is with a for...in loop. The problem with a for...in loop is that it iterates through properties in the Prototype chain. When you loop through an object with the for...in loop, you need to check if the property belongs to the object. You can do this with hasOwnProperty. for (var property in object) { if (object.hasOwnProperty(property)) { // Do things here } } We no longer have to rely on for...in and hasOwnProperty now. There’s a better way.

    A better way to loop through objects

    The better way to loop through objects is first to convert the object into an array. Then, you loop through the array. You can convert an object into an array with three methods:
    1. Object.keys
    2. Object.values
    3. Object.entries

    Object.keys

    Object.keys creates an array that contains the properties of an object. const fruits = { apple: 28, orange: 17, pear: 54, } console.log(Object.keys(fruits)) // [apple, orange, pear]

    Object.values

    Object.values creates an array that contains the values of every property in an object. Here’s an example: const fruits = { apple: 28, orange: 17, pear: 54, } const values = Object.values(fruits) console.log(values) // [28, 17, 54]

    Object.entries

    Object.entries creates an array of arrays. Each inner array has two item. The first item is the property; the second item is the value. Here’s an example: const fruits = { apple: 28, orange: 17, pear: 54, } const entries = Object.entries(fruits) console.log(entries) // [ // [apple, 28], // [orange, 17], // [pear, 54] // ] My favorite of the three is Object.entries because you get both the key and property values.

    Looping through the array

    Once you’ve converted the object into an array with Object.keys, Object.values, or Object.entries, you can loop through it as if it was a normal array. // Looping through arrays created from Object.keys const keys = Object.keys(fruits) for (const key of keys) { console.log(key) } // Results: // apple // orange // pear If you use Object.entries you might want to destructure the array into its key and property. for (const [fruit, count] of entries) { console.log(`There are ${count} ${fruit}s`) } // Result // There are 28 apples // There are 17 oranges // There are 54 pears

    Get element of JS object with an index

    Get element of JS object with an index myobj[Object.keys(myobj)[0]];

    Wrapping up

    The better way to loop through objects is first convert it into an array with one of these three methods.
    1. Object.keys
    2. Object.values
    3. Object.entries
    Then, you loop through the results like a normal array.

    Reading CSV File With HTML5 File API

    Reading CSV File With HTML5 File API

    JS access local file

    from to access status local js local file error, CORS server file OK server js local file error, CORS server file error in some server local server js local file ? server file ? use file api: Reading CSV File With HTML5 File API

    fairyDustCursorJS

    fairyDustCursorJS

    copying strings to the clipboard

    copying strings to the clipboard function copyStringToClipboard (str) { // Create new element var el = document.createElement('textarea'); // Set value (string to be copied) el.value = str; // Set non-editable to avoid focus and move outside of view el.setAttribute('readonly', ''); el.style = {position: 'absolute', left: '-9999px'}; document.body.appendChild(el); // Select text inside element el.select(); // Copy text to clipboard document.execCommand('copy'); // Remove temporary element document.body.removeChild(el); } Note: If the user selected anything when you ran the function, this selection will be cleared. If you need to preserve the selection, see this Hackernoon article for a more elaborate solution.. You can use it like this: // Usage example: copyStringToClipboard("abc123"); It works by adding a temporary textarea element onto the DOM which is moved outside (credits to Angelos Charalis on Hackernoon for the original idea) the viewport in order to avoid wreaking havoc on screenreaders etc.

    slide and fade functions

    $(".btn1").click(function(){ $("p").slideUp(); }); $(".btn2").click(function(){ $("p").slideDown(); }); $("button").click(function(){ $("#div1").fadeToggle(); $("#div2").fadeToggle("slow"); $("#div3").fadeToggle(3000); });

    TypeScript in 5 minutes

    TypeScript in 5 minutes

    Prototype

    JavaScript Prototype

    Prototype with Examples

    JavaScript is a prototype-based language, therefore understanding the prototype object is one of the most important concepts which JavaScript practitioners need to know. Before reading this article, you will need to have a basic understanding of the this reference in JavaScript.

    Prototype object

    For the sake of clarity, let’s examine the following example: function Point2D(x, y) { this.x = x; this.y = y;} As Point2D function is declared, a default property named prototype will be created for it (note that, in JavaScript, a function is also an object). The prototype property is an object which contains a constructor property and its value is Point2D function: Point2D.prototype.constructor = Point2D. And when you call Point2D with new keyword, newly created objects will inherit all properties from Point2D.prototype. To check that, you can add a method named move into Point2D.prototype as follows: Point2D.prototype.move = function(dx, dy) { this.x += dx; this.y += dy;} var p1 = new Point2D(1, 2); p1.move(3, 4); console.log(p1.x); // 4 console.log(p1.y); // 6 The Point2D.prototype is called prototype object or prototype of p1 object and for any other object created with new Point2D(...) syntax. You can add more properties to Point2D.prototype object as you like. The common pattern is declare methods to Point2D.prototype and other properties will be declared in constructor function. Built-in objects in JavaScript are constructed in a similar manner. For example: Object.prototype is inherited by all objects and it has no prototype (its prototype is null).

    Prototype chain

    The prototype chain mechanism is simple: When you access a property p on object obj, the JavaScript engine will search this property inside obj object. If the engine fails to search, it continues searching in the prototype of obj object and so on until reaching Object.prototype. If after the search has finished, and nothing has been found the result will be undefined. For example: var obj1 = { a: 1, b: 2}; var obj2 = Object.create(obj1); obj2.a = 2; console.log(obj2.a); // 2 console.log(obj2.b); // 2 console.log(obj2.c); // undefined In above snippet, the statement var obj2 = Object.create(obj1) will create obj2 object with prototype obj1 object. In other words, obj1 becomes the prototype of obj2 instead of Object.prototype by default. As you can see, b is not a property of obj2, you can still access it via the prototype chain. For c property, however, you get undefined value because it can’t be found in obj1 and Object.prototype.

    Classes

    In ES2016, we now get to use the Class keyword as well as the methods mentioned above to manipulate prototype. The JavaScript Class appeals to developers from OOP backgrounds, but it’s essentially doing the same thing as above. class Rectangle { constructor(height, width) { this.height = height this.width = width } get area() { return this.calcArea() } calcArea() { return this.height * this.width }} const square = new Rectangle(10, 10) console.log(square.area) // 100 This is basically the same as: function Rectangle(height, width) { this.height = height this.width = width} Rectangle.prototype.calcArea = function calcArea() { return this.height * this.width} The getter and setter methods in classes bind an Object property to a function that will be called when that property is looked up. It’s just syntactic sugar to help make it easier to look up or set properties.

    Multiple Onload Functions

    https://www.htmlgoodies.com/beyond/javascript/article.php/3724571/Using-Multiple-JavaScript-Onload-Functions.htm Using Multiple JavaScript Onload Functions window.onload = func1; execute the script when page is loaded <body onload="func1(); func2();"> linking of multiple events onloaded <body onload="func1(); onkeypress="chkKey()"> on multiple events window.onload = start; function start() { func1(); func2();} linking of multiple events by function onloaded window.addEventListener("load", myInit, true); function myInit(){ // call your functions here.... }; create an init function manually this can call that set of functions anytime

    non-capturing group (?:)

    non-capturing group (?:)

    5 JavaScript Web Scraping Libraries and Tools for nodeJs

    Exploring web scraping libraries and tools for JavaScript.
    1. Request 2. Cheerio 3. Osmosis 4. Puppeteer 5. Apify SDK

    1. Request (Aka HTTP Client) :

    Request For example, if you want to pull down the contents of a page : const request = require('request'); request('http://stackabuse.com', function(err, res, body) { console.log(body); }); Quick start Guide with request

    2. Cheerio (Aka Parser) :

    Cheerio Web Scraping note (cheerio)

    3. Osmosis (Aka Parser) :

    Osmosis Using node-osmosis (with examples)

    4. Puppeteer (Aka Headless Chrome Browser for Automation) :

    Puppeteer Tips and Tricks for Web Scraping with Puppeteer

    5. Apify SDK (Aka The Complete Web Scraping Framework) :

    Apify SDK It can be used either stand-alone in your own applications or in actors running on the Apify Cloud. Getting Started with Apify with Examples

    what is this "require?"

    require() is not part of the standard JavaScript API. But in Node.js, it's a built-in function with a special purpose: to load modules. Modules are a way to split an application into separate files instead of having all of your application in one file. This concept is also present in other languages with minor differences in syntax and behavior, like C's include, PHP's use, Python's import, and so on. One big difference between Node.js modules and browser JavaScript is how one script's code is accessed from another script's code. In browser JavaScript, scripts are added via the <script> element. When they execute, they all have direct access to the global scope, a "shared space" among all scripts. Any script can freely define/modify/remove/call anything on the global scope. In Node.js, each module has its own scope. A module cannot directly access things defined in another module unless it chooses to expose them. To expose things from a module, they must be assigned to exports or module.exports. For a module to access another module's exports or module.exports, it must use require(). In your code, var pg = require('pg'); loads the pg module, a PostgreSQL client for Node.js. This allows your code to access functionality of the PostgreSQL client's APIs via the pg variable. Why does it work in node but not in a webpage? require(), module.exports and exports are APIs of a module system that is specific to Node.js. Browsers do not implement this module system. Also, before I got it to work in node, I had to do npm install pg. What's that about? NPM is a package repository service that hosts published JavaScript modules. npm install is a command that lets you download packages from their repository. Where did it put it, and how does Javascript find it? Node.js has very detailed documentation on how modules find other modules. But in a gist, it puts all the downloaded modules in node_modules in the directory where you ran npm install. the request module to webscrap const request = require('request'); request('http://stackabuse.com', function(err, res, body) { console.log(body); });

    create a table

    var table = document.getElementById("myTable"); var row = table.insertRow(0); var cell1 = row.insertCell(0); var cell2 = row.insertCell(1); cell1.innerHTML = "NEW CELL1"; cell2.innerHTML = "NEW CELL2"; create a table using a loop
    var table = document.createElement('table'), tr, td, row, cell; for (row = 0; row < 10; row++) { tr = document.createElement('tr'); for (cell = 0; cell < 22; cell++) { td = document.createElement('td'); tr.appendChild(td); td.innerHTML = row * 22 + cell + 1; } table.appendChild(tr); } document.getElementById('container').appendChild(table); create an empty row of 22 cells, clone it 10 times, and then add the numbers to the cells. var table = document.createElement('table'), tr = document.createElement('tr'), cells, i; for (i = 0; i < 22; i++) { // Create an empty row tr.appendChild(document.createElement('td')); } for (i = 0; i < 10; i++) { // Add 10 copies of it to the table table.appendChild(tr.cloneNode(true)); } cells = table.getElementsByTagName('td'); // get all of the cells for (i = 0; i < 220; i++) { // number them cells[i].innerHTML = i + 1; } document.getElementById('container').appendChild(table); And a third option: add the cells in a single loop, making a new row every 22 cells. var table = document.createElement('table'), tr, td, i; for (i = 0; i < 220; i++) { if (i % 22 == 0) { // every 22nd cell (including the first) tr = table.appendChild(document.createElement('tr')); // add a new row } td = tr.appendChild(document.createElement('td')); td.innerHTML = i + 1; } document.getElementById('container').appendChild(table); HTML DOM createDocumentFragment() Method HTML DOM createDocumentFragment() Method Example Create a documentFragment node and append a child to it (a list item). Then, change the list item's node value and insert it as the last child of the list: var d = document.createDocumentFragment(); d.appendChild(document.getElementsByTagName("LI")[0]); d.childNodes[0].childNodes[0].nodeValue = "Milk"; document.getElementsByTagName("UL")[0].appendChild(d); Table rows Collection

    check keyboard arrow key

    document.onkeydown = checkKey; function checkKey(e) { e = e || window.event; if (e.keyCode == '38') { // up arrow } else if (e.keyCode == '40') { // down arrow } else if (e.keyCode == '37') { // left arrow } else if (e.keyCode == '39') { // right arrow } } function getChar(event) { if (event.which!=0 && event.charCode!=0) { return String.fromCharCode(event.which) // the rest } else { return event.keyCode // special key } }

    Top 10 jQuery functions to Plain Old JavaScript

    Top 10 jQuery functions
    1 $(document).ready(..)
    2) $(…).HTML()
    3) $(…).Append
    4) $(…).prepend()
    5) $(…).empty()
    6) $(…).Attr(name)
    7) $(…).val()
    8, 9) $(…).on() | $(…).off()
    10) $(…).toggle()
    Conclusion These are my top most commonly use jQuery functions converted to Plain Old JavaScript. Sometimes I need to create a simple static HTML or landing page, and I don’t feel like bringing in any libraries or bloatware. For those cases I just use plain old JavaScript to get the job done, and honestly it feels good to know how things work. So here is my top 10 list, I also use this as reference and now sharing with you. If you like to follow along go to the GitHub page here, and feel free to contribute: https://github.com/omarld/jqueryToPlainJS Before starting, the titles are the jQuery functions to be converted to plain old JavaScript. That will follow with a brief description of what it is supposed to do, followed by the converted JavaScript code with some additional notes.

    1 $(document).ready(..)

    Check that document has loaded and ready to execute your scripts. let isLoaded = false; let myOnLoadCallBack = function(){ isLoaded = true; //my stuff here } document.addEventListener("DOMContentLoaded", myOnLoadCallBack()); document.addEventListener('readystatechange', (event) => { if (document.readyState === 'complete' && !isLoaded) { myOnLoadCallBack(); } ); Using DOMContentLoaded event listener, this is triggered when the DOM tree has been built but none of other resources have been loaded yet (ie styles, images). DOMContentLoaded also waits for any scripts to be loaded, if there are any script tags found in the HTML document. There is catch when loading styles if there is a script tag after your styles. In this case it’s for styles to be loaded before the script, in case the script modifies any styles. DOMContentLoaded is not supported by IE 8 or less. In case you have the bad luck of having to support IE 8, you should use document.readyState. The different ready states are:

    2) $(…).HTML()

    Find the value of an existing DOM element, or insert some content. To find existing value, just reference the innerHTML property. var content = document.querySelector("section#html div.content p.retrieve").innerHTML; To insert some content, assign innerHTML to the new content which can contain HTML tags. Note, this will replace any existing content. document.querySelector("section#html div.results p.sample").innerHTML = “<p>Starting a new paragraph</p>”;

    3) $(…).Append

    Insert some HTML at the end of an existing element. First we need to find/get the element where we want to insert our new content. var appendEl = document.querySelector("section#append div.content div.results"); Next create the element we want to insert. var childEl = document.createElement("div"); childEl.innerHTML = "<p>New <strong>child</strong> Content!</p>" Lastly, insert the element. //appending appendEl.appendChild(childEl); Sure this took three steps to get this done, but we can simplify a bit.
    First lets create the new element. var childEl = document.createElement("div"); childEl.innerHTML = "<p>New <strong>child</strong> Content!</p>" Next let’s find and insert new element in one line. document.querySelector("section#append div.content div.results").appendChild(childEl); If you want to simplify this further or if you find yourself doing this a lot, you can create a wrapper function to do this.

    4) $(…).prepend()

    Very similar to append above, the only difference is that this inserts at the beginning of the element. For this we will jump into the simplified solution. Create new element to insert. var newDiv = document.createElement("div"); var textNode = document.createTextNode("new content to inserted!"); newDiv.appendChild(textNode); Find existing element and insert new element. document.querySelector("section#prepend div.content p#existing").insertBefore(newDiv, prependEl.firstChild);

    5) $(…).empty()

    Empty or clear out a DOM element. Initially you might think, lets just assign innerHTML property to an empty string. This would be half right, but then what happens if the target element has child DOM elements? We’ll get to that, it is also simple. First let’s start by clearing out content of an existing element. document.getElementById("empty-content").innerHtml = “”; Okay, so now how do we do all inner DOM elements? For that, let’s clear existing content and then lets remove any child DOM elements in a loop. var content = document.getElementById("empty-content"); content.innerHtml = ""; while(content.firstChild){ content.removeChild(content.firstChild); } The while loop iterates until there are no more children to remove.

    6) $(…).Attr(name)

    Get the attribute value of an existing DOM element, or set attribute. The important point to remember about this, is that not all DOM elements have the same attributes. For example a check box vs a button (a button would not have the checked attribute). Let’s start by getting the checked attribute of a check box. let isChecked = document.querySelector("div#attributes input#my-check-box").getAttribute("checked"); Now let’s see how we can set that same attribute. var el = document.querySelector("div#attributes input#my-check-box"); We can access the JavaScript property to change its state. el.checked = true; You might have noticed that I referred to the checked key as a JavaScript property. What is the difference between element attribute and JavaScript property? In simple terms, properties are JavaScript inherited keys from element attributes. This means you can access the DOM elements attributes as JavaScript object properties. Here are a few important points to know about properties vs attributes.

    7) $(…).val()

    Get the value of the matched DOM element. This is also a simple one, let’s start with getting the value of existing element. To make these command clear, I have split them out. Although this can be done in one line. var content = document.querySelector("#input"); var lnameValue = content.querySelector("input[name='lname']").value; Setting value is just as simple, and can also be done in one line. content.querySelector("input[name='fname']").value = "Some random value" ; Similar to using innerHTML to set content, this also overrides any values the element currently has.

    8, 9) $(…).on() | $(…).off()

    To add or remove events from an element use either on() or off() accordingly. Adding event handler. document.getElementById("my-button").addEventListener("click", function(evt){ //my custom code here }); Removing event handler, here we need to do extra checks for browser supported properties. var toggleFunction = function(){...} if (toggleBtn.removeEventListener) { // For all major browsers, except IE 8 and earlier toggleBtn.removeEventListener("click", toggleFunction); } else if (toggleBtn.detachEvent) { // For IE 8 and earlier versions toggleBtn.detachEvent("click", toggleFunction) } Here are a few things to note when adding or removing events handlers. One way to remove all event handlers without being explicit, is to clone the element and replace it. This will also get rid of any attached events to child elements. Removing all elements. var currEl = document.getElementById("button"); var cloneEl= currEl.cloneNode(true); currEl.parentNode.replaceChild(cloneEl, currEl);

    10) $(…).toggle()

    Toggle display on an element, this can be done a couple of ways. Each approach has has different results. You need to decide which behavior you want. First way is to change the elements display attribute to none to remove element from the DOM, and set it to initial to set it back. Important point here is that this will impact your layout, and shift elements if you are toggling display. Here we are toggling display on an image element by directly accessing the elements style property. if(imgEl.style.display && imgEl.style.display === "none"){ imgEl.style.display = "initial"; } else { imgEl.style.display = "none"; } Second approach is to change the elements visibility, which will hide the element and retain layout. if(imgEl.style.visibility && imgEl.style.visibility === "hidden"){ imgEl.style.visibility = "initial"; } else { imgEl.style.visibility = "hidden"; };

    Conclusion

    If you have been using libraries and JavaScript frameworks, it is easy to lose sight on how simple some of implementations are. But most of all, you also lose sight into some core basic understanding of how the DOM works. Having a good understanding the DOM can serve you well not just on design but also on debugging issues. Those were just some of my most often used functions when I am trying to keep things simple. Now I am sharing it with you if ever feel like just writing your own rather than adding bloat-ware to your application.

    Some javascript Essays

    Fractal animation
    JavaScript Image Manipulation Program
    Top 10 jQuery functions to Plain Old JavaScript
    Framer Motion, React library to power production-ready animations
    HIGHER-ORDER FUNCTIONS
    IMPLEMENTING AN EFFICIENT LRU CACHE IN JAVASCRIPT
    How To Master Async/Await With This Real World Example
    JavaScript Algorithms and Data Structures
    New Node.js 12 features will see it disrupt AI, IoT and more surprising areas
    12 Tips for Improving JavaScript Performance

    The XMLHttpRequest Object

    All modern browsers have a built-in XMLHttpRequest object to request data from a server. All major browsers have a built-in XML parser to access and manipulate XML.

    The XMLHttpRequest Object

    The XMLHttpRequest object can be used to request data from a web server. The XMLHttpRequest object is a developer's dream, because you can:
  • Update a web page without reloading the page
  • Request data from a server - after the page has loaded
  • Receive data from a server - after the page has loaded
  • Send data to a server - in the background
  • XMLHttpRequest Example

    When you type a character in the input field below, an XMLHttpRequest is sent to the server, and some name suggestions are returned (from the server):

    Example

    Start typing a name in the input field below: <form action=""> Name: <input type="text" id="txt1" onkeyup="showHint(this.value)" size="20"> </form> Suggestions: <span id="txtHint"></span>

    Sending an XMLHttpRequest

    All modern browsers have a built-in XMLHttpRequest object. A common JavaScript syntax for using it looks much like this:

    Example

    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
    // Action to be performed when the document is read;
    }
    };
    xhttp.open("GET", "filename", true);
    xhttp.send(); Try it Yourself »

    Creating an XMLHttpRequest Object

    The first line in the example above creates an XMLHttpRequest object: var xhttp = new XMLHttpRequest();

    XMLHttpRequest Properties and Methods

    Method Description
    new XMLHttpRequest() Creates a new XMLHttpRequest object
    open(method, url, async) Specifies the type of request
    method: the type of request: GET or POST
    url: the file location
    async: true (asynchronous) or false (synchronous)
    send() Sends a request to the server (used for GET)
    send(string) Sends a request string to the server (used for POST)
    onreadystatechange A function to be called when the readyState property changes
    readyState The status of the XMLHttpRequest
    0: request not initialized
    1: server connection established
    2: request received
    3: processing request
    4: request finished and response is ready
    status 200: OK
    404: Page not found
    responseText The response data as a string
    responseXML The response data as XML data

    Access Across Domains

    For security reasons, modern browsers do not allow access across domains. This means that both the web page and the XML file it tries to load, must be located on the same server. The examples on W3Schools all open XML files located on the W3Schools domain. If you want to use the example above on one of your own web pages, the XML files you load must be located on your own server.

    The responseText Property

    The responseText property returns the response as a string. If you want to use the response as a text string, use the responseText property:

    Example

    document.getElementById("demo").innerHTML = xmlhttp.responseText; Try it Yourself »

    The responseXML Property

    The responseXML property returns the response as an XML DOM object. If you want to use the response as an XML DOM object, use the responseXML property:

    Example

    Request the file cd_catalog.xml and use the response as an XML DOM object: xmlDoc = xmlhttp.responseXML;
    txt = ";
    x = xmlDoc.getElementsByTagName("ARTIST");
    for (i = 0; i < x.length; i++) {
    txt += x[i].childNodes[0].nodeValue + "<br>";
    }
    document.getElementById("demo").innerHTML = txt;Try it Yourself »

    GET or POST?

    GET is simpler and faster than POST, and can be used in most cases. However, always use POST requests when:

    The url - A File On a Server

    The url parameter of the open() method, is an address to a file on a server: xmlhttp.open("GET", "xmlhttp_info.txt", true); The file can be any kind of file, like .txt and .xml, or server scripting files like .asp and .php (which can perform actions on the server before sending the response back).

    XML Parser

    All modern browsers have a built-in XML parser. The XML Document Object Model (the XML DOM) contains a lot of methods to access and edit XML. However, before an XML document can be accessed, it must be loaded into an XML DOM object. An XML parser can read plain text and convert it into an XML DOM object.

    XML DOM Remove Nodes

    XML DOM Remove Nodes The removeChild() method removes a specified node. The removeAttribute() method removes a specified attribute.

    Parsing a Text String

    This example parses a text string into an XML DOM object, and extracts the info from it with JavaScript:

    Example

    <html>
    <body>

    <p id="demo"></p>

    <script>
    var text, parser, xmlDoc;

    text = "<bookstore><book>" +
    "<title>Everyday Italian</title>" +
    "<author>Giada De Laurentiis</author>" +
    "<year>2005</year>" +
    "</book></bookstore>";

    parser = new DOMParser();
    xmlDoc = parser.parseFromString(text,"text/xml");

    document.getElementById("demo").innerHTML =
    xmlDoc.getElementsByTagName("title")[0].childNodes[0].nodeValue;
    </script>

    </body>
    </html> Try it Yourself »

    Old Browsers (IE5 and IE6)

    Old versions of Internet Explorer (IE5 and IE6) do not support the XMLHttpRequest object. To handle IE5 and IE6, check if the browser supports the XMLHttpRequest object, or else create an ActiveXObject:

    Example

    if (window.XMLHttpRequest) {
    // code for modern browsers
    xmlhttp = new XMLHttpRequest();
    } else {
    // code for old IE browsers
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    } Try it Yourself » Old versions of Internet Explorer (IE5 and IE6) do not support the DOMParser object. To handle IE5 and IE6, check if the browser supports the DOMParser object, or else create an ActiveXObject:

    Example

    if (window.DOMParser) {
    // code for modern browsers
    parser = new DOMParser();
    xmlDoc = parser.parseFromString(text,"text/xml");
    } else {
    // code for old IE browsers
    xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
    xmlDoc.async = false;
    xmlDoc.loadXML(text);
    } Try it Yourself »

    More Examples

    Retrieve header information with getAllResponseHeaders() Retrieve header information of a resource (file). Retrieve specific header information with getResponseHeader() Retrieve specific header information of a resource (file). Retrieve the content of an ASP file How a web page can communicate with a web server while a user type characters in an input field. Retrieve content from a database How a web page can fetch information from a database with the XMLHttpRequest object. Retrieve the content of an XML file Create an XMLHttpRequest to retrieve data from an XML file and display the data in an HTML table.

    ActiveXObject

    ActiveXObject is non-standard and only supported by Internet Explorer on Windows.

    MySQL Database

    To be able to experiment with the code examples, you should have MySQL installed on your computer. You can download a free MySQL database at https://www.mysql.com/downloads/.

    Install MySQL Driver

    Once you have MySQL up and running on your computer, you can access it by using Node.js. To access a MySQL database with Node.js, you need a MySQL driver. This tutorial will use the "mysql" module, downloaded from NPM. To download and install the "mysql" module, open the Command Terminal and execute the following: C:\Users\Your Name>npm install mysql Now you have downloaded and installed a mysql database driver. Node.js can use this module to manipulate the MySQL database: var mysql = require('mysql');

    Create Connection

    Start by creating a connection to the database. Use the username and password from your MySQL database. demo_db_connection.js var mysql = require('mysql');

    var con = mysql.createConnection({
      host: "localhost",
      user: "yourusername",
      password: "yourpassword"
    });

    con.connect(function(err) {
      if (err) throw err;
      console.log("Connected!");
    });
    Run example » Save the code above in a file called "demo_db_connection.js" and run the file: Run "demo_db_connection.js" C:\Users\Your Name>node demo_db_connection.js Which will give you this result: Connected! Now you can start querying the database using SQL statements.

    Query a Database

    Use SQL statements to read from (or write to) a MySQL database. This is also called "to query" the database. The connection object created in the example above, has a method for querying the database: con.connect(function(err) {
      if (err) throw err;
      console.log("Connected!");
    con.query(sql, function(err, result) {
        if (err) throw err;
        console.log("Result: " + result);
      });
    }); The query method takes an sql statements as a parameter and returns the result. Learn how to read, write, delete, and update a database in the next chapters. Read more about SQL statements in our SQL Tutorial.

    AJAX Database Example

    AJAX can be used for interactive communication with a database. The following example will demonstrate how a web page can fetch information from a database with AJAX:

    Example

    <form action=""> <select name="customers" onchange="showCustomer(this.value)"> <option value="">Select a customer:</option> <option value="ALFKI">Alfreds Futterkiste</option> <option value="NORTS ">North/South</option> <option value="WOLZA">Wolski Zajazd</option> </select> </form>
    Customer info will be listed here... Try it Yourself »

    Example Explained - The showCustomer() Function

    When a user selects a customer in the dropdown list above, a function called showCustomer() is executed. The function is triggered by the onchange event:

    showCustomer

    function showCustomer(str) {
      var xhttp;
      if (str == ") {
        document.getElementById("txtHint").innerHTML = ";
        return;
      }
      xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
        document.getElementById("txtHint").innerHTML = this.responseText;
        }
      };
      xhttp.open("GET", "getcustomer.php?q="+str, true);
      xhttp.send();
    } The showCustomer() function does the following:
  • Check if a customer is selected
  • Create an XMLHttpRequest object
  • Create the function to be executed when the server response is ready
  • Send the request off to a file on the server
  • Notice that a parameter (q) is added to the URL (with the content of the dropdown list)
  • The AJAX Server Page

    The page on the server called by the JavaScript above is a PHP file called "getcustomer.php". The source code in "getcustomer.php" runs a query against a database, and returns the result in an HTML table: <?php
    $mysqli = new mysqli("servername", "username", "password", "dbname");
    if($mysqli->connect_error) {
      exit('Could not connect');
    }

    $sql = "SELECT customerid, companyname, contactname, address, city, postalcode, country
    FROM customers WHERE customerid = ?";

    $stmt = $mysqli->prepare($sql);
    $stmt->bind_param("s", $_GET['q']);
    $stmt->execute();
    $stmt->store_result();
    $stmt->bind_result($cid, $cname, $name, $adr, $city, $pcode, $country);
    $stmt->fetch();
    $stmt->close();

    echo "<table>";
    echo "<tr>";
    echo "<th>CustomerID</th>";
    echo "<td>" . $cid . "</td>";
    echo "<th>CompanyName</th>";
    echo "<td>" . $cname . "</td>";
    echo "<th>ContactName</th>";
    echo "<td>" . $name . "</td>";
    echo "<th>Address</th>";
    echo "<td>" . $adr . "</td>";
    echo "<th>City</th>";
    echo "<td>" . $city . "</td>";
    echo "<th>PostalCode</th>";
    echo "<td>" . $pcode . "</td>";
    echo "<th>Country</th>";
    echo "<td>" . $country . "</td>";
    echo "</tr>";
    echo "</table>";
    ?>

    ES2018 Features

    The ninth edition of the ECMAScript standard, officially known as ECMAScript 2018 (or ES2018 for short), was released in June 2018. Starting with ES2016, new versions of ECMAScript specifications are released yearly rather than every several years and add fewer features than major editions used to. The newest edition of the standard continues the yearly release cycle by adding four new RegExp features, rest/spread properties, asynchronous iteration, and Promise.prototype.finally. Additionally, ES2018 drops the syntax restriction of escape sequences from tagged templates. These new changes are explained in the subsections that follow.

    The Rest/Spread Properties

    One of the most interesting features added to ES2015 was the spread operator. This operator makes copying and merging arrays a lot simpler. Rather than calling the concat() or slice() method, you could use the ... operator: const arr1 = [10, 20, 30]; // make a copy of arr1 const copy = [...arr1]; console.log(copy); // → [10, 20, 30] const arr2 = [40, 50]; // merge arr2 with arr1 const merge = [...arr1, ...arr2]; console.log(merge); // → [10, 20, 30, 40, 50] The spread operator also comes in handy in situations where an array must be passed in as separate arguments to a function. For example: const arr = [10, 20, 30] // equivalent to // console.log(Math.max(10, 20, 30)); console.log(Math.max(...arr)); // → 30 ES2018 further expands this syntax by adding spread properties to object literals. With the spread properties you can copy own enumerable properties of an object onto a new object. Consider the following example: const obj1 = { a: 10, b: 20 }; const obj2 = { ...obj1, c: 30 }; console.log(obj2); // → {a: 10, b: 20, c: 30} In this code, the ... operator is used to retrieve the properties of obj1 and assign them to obj2. Prior to ES2018, attempting to do so would throw an error. If there are multiple properties with the same name, the property that comes last will be used: const obj1 = { a: 10, b: 20 }; const obj2 = { ...obj1, a: 30 }; console.log(obj2); // → {a: 30, b: 20} Spread properties also provide a new way to merge two or more objects, which can be used as an alternative to the Object.assign() method: const obj1 = {a: 10}; const obj2 = {b: 20}; const obj3 = {c: 30}; // ES2018 console.log({...obj1, ...obj2, ...obj3}); // → {a: 10, b: 20, c: 30} // ES2015 console.log(Object.assign({}, obj1, obj2, obj3)); // → {a: 10, b: 20, c: 30} Note, however, that spread properties do not always produce the same result as Object.assign(). Consider the following code: Object.defineProperty(Object.prototype, 'a', { set(value) { console.log('set called!'); } }); const obj = {a: 10}; console.log({...obj}); // → {a: 10} console.log(Object.assign({}, obj)); // → set called! // → {} In this code, the Object.assign() method executes the inherited setter property. Conversely, the spread properties simply ignore the setter. It's important to remember that spread properties only copy enumerable properties. In the following example, the type property won’t show up in the copied object because its enumerable attribute is set to false: const car = { color: 'blue' }; Object.defineProperty(car, 'type', { value: 'coupe', enumerable: false }); console.log({...car}); // → {color: "blue"} Inherited properties are ignored even if they are enumerable: const car = { color: 'blue' }; const car2 = Object.create(car, { type: { value: 'coupe', enumerable: true, } }); console.log(car2.color); // → blue console.log(car2.hasOwnProperty('color')); // → false console.log(car2.type); // → coupe console.log(car2.hasOwnProperty('type')); // → true console.log({...car2}); // → {type: "coupe"} In this code, car2 inherits the color property from car. Because spread properties only copy the own properties of an object, color is not included in the return value. Keep in mind that spread properties can only make a shallow copy of an object. If a property holds an object, only the reference to the object will be copied: const obj = {x: {y: 10}}; const copy1 = {...obj}; const copy2 = {...obj}; console.log(copy1.x === copy2.x); // → true The x property in copy1 refers to the same object in memory that x in copy2 refers to, so the strict equality operator returns true. Another useful feature added to ES2015 was rest parameters, which enabled JavaScript programmers to use ... to represent values as an array. For example: const arr = [10, 20, 30]; const [x, ...rest] = arr; console.log(x); // → 10 console.log(rest); // → [20, 30] Here, the first item in arr is assigned to x, and remaining elements are assigned to the rest variable. This pattern, called array destructuring, became so popular that the Ecma Technical Committee decided to bring similar functionality to objects: const obj = { a: 10, b: 20, c: 30 }; const {a, ...rest} = obj; console.log(a); // → 10 console.log(rest); // → {b: 20, c: 30} This code uses the rest properties in a destructuring assignment to copy the remaining own enumerable properties into a new object. Note that rest properties must always appear at the end of the object, otherwise an error is thrown: const obj = { a: 10, b: 20, c: 30 }; const {...rest, a} = obj; // → SyntaxError: Rest element must be last element Also keep in mind that using multiple rest syntaxes in an object causes an error unless they are nested: const obj = { a: 10, b: { x: 20, y: 30, z: 40 } }; const {b: {x, ...rest1}, ...rest2} = obj; // no error const {...rest, ...rest2} = obj; // → SyntaxError: Rest element must be last element

    Asynchronous Iteration

    Iterating over a collection of data is an important part of programming. Prior to ES2015, JavaScript provided statements such as for, for...in, and while, and methods such as map(), filter(), and forEach() for this purpose. To enable programmers to process the elements in a collection one at a time, ES2015 introduced the iterator interface. An object is iterable if it has a Symbol.iterator property. In ES2015, strings and collections objects such as Set, Map, and Array come with a Symbol.iterator property and thus are iterable. The following code gives an example of how to access the elements of an iterable one at a time: const arr = [10, 20, 30]; const iterator = arr[Symbol.iterator](); console.log(iterator.next()); // → {value: 10, done: false} console.log(iterator.next()); // → {value: 20, done: false} console.log(iterator.next()); // → {value: 30, done: false} console.log(iterator.next()); // → {value: undefined, done: true} Symbol.iterator is a well-known symbol specifying a function that returns an iterator. The primary way to interact with an iterator is the next() method. This method returns an object with two properties: value and done. The value property contains the value of the next element in the collection. The done property contains either true or false denoting whether or not the end of the collection has reached. By default, a plain object is not iterable, but it can become iterable if you define a Symbol.iterator property on it, as in this example: const collection = { a: 10, b: 20, c: 30, [Symbol.iterator]() { const values = Object.keys(this); let i = 0; return { next: () =&gt; { return { value: this[values[i++]], done: i &gt; values.length } } }; } }; const iterator = collection[Symbol.iterator](); console.log(iterator.next()); // → {value: 10, done: false} console.log(iterator.next()); // → {value: 20, done: false} console.log(iterator.next()); // → {value: 30, done: false} console.log(iterator.next()); // → {value: undefined, done: true} This object is iterable because it defines a Symbol.iterator property. The iterator uses the Object.keys() method to get an array of the object's property names and then assigns it to the values constant. It also defines a counter variable and gives it an initial value of 0. When the iterator is executed it returns an object that contains a next() method. Each time the next() method is called, it returns a {value, done} pair, with value holding the next element in the collection and done holding a Boolean indicating if the iterator has reached the need of the collection. While this code works perfectly, it’s unnecessarily complicated. Fortunately, using a generator function can considerably simplify the process: const collection = { a: 10, b: 20, c: 30, [Symbol.iterator]: function * () { for (let key in this) { yield this[key]; } } }; const iterator = collection[Symbol.iterator](); console.log(iterator.next()); // → {value: 10, done: false} console.log(iterator.next()); // → {value: 20, done: false} console.log(iterator.next()); // → {value: 30, done: false} console.log(iterator.next()); // → {value: undefined, done: true} Inside this generator, a for...in loop is used to enumerate over the collection and yield the value of each property. The result is exactly the same as the previous example, but it’s greatly shorter. A downside of iterators is that they are not suitable for representing asynchronous data sources. ES2018’s solution to remedy that is asynchronous iterators and asynchronous iterables. An asynchronous iterator differs from a conventional iterator in that, instead of returning a plain object in the form of {value, done}, it returns a promise that fulfills to {value, done}. An asynchronous iterable defines a Symbol.asyncIterator method (instead of Symbol.iterator) that returns an asynchronous iterator. An example should make this clearer: const collection = { a: 10, b: 20, c: 30, [Symbol.asyncIterator]() { const values = Object.keys(this); let i = 0; return { next: () =&gt; { return Promise.resolve({ value: this[values[i++]], done: i &gt; values.length }); } }; } }; const iterator = collection[Symbol.asyncIterator](); console.log(iterator.next().then(result =&gt; { console.log(result); // → {value: 10, done: false} })); console.log(iterator.next().then(result =&gt; { console.log(result); // → {value: 20, done: false} })); console.log(iterator.next().then(result =&gt; { console.log(result); // → {value: 30, done: false} })); console.log(iterator.next().then(result =&gt; { console.log(result); // → {value: undefined, done: true} })); Note that it’s not possible to use an iterator of promises to achieve the same result. Although a normal, synchronous iterator can asynchronously determine the values, it still needs to determine the state of “done” synchronously. Again, you can simplify the process by using a generator function, as shown below: const collection = { a: 10, b: 20, c: 30, [Symbol.asyncIterator]: async function * () { for (let key in this) { yield this[key]; } } }; const iterator = collection[Symbol.asyncIterator](); console.log(iterator.next().then(result =&gt; { console.log(result); // → {value: 10, done: false} })); console.log(iterator.next().then(result =&gt; { console.log(result); // → {value: 20, done: false} })); console.log(iterator.next().then(result =&gt; { console.log(result); // → {value: 30, done: false} })); console.log(iterator.next().then(result =&gt; { console.log(result); // → {value: undefined, done: true} })); Normally, a generator function returns a generator object with a next() method. When next() is called it returns a {value, done} pair whose value property holds the yielded value. An async generator does the same thing except that it returns a promise that fulfills to {value, done}. An easy way to iterate over an iterable object is to use the for...of statement, but for...of doesn't work with async iterables as value and done are not determined synchronously. For this reason, ES2018 provides the for...await...of statement. Let’s look at an example: const collection = { a: 10, b: 20, c: 30, [Symbol.asyncIterator]: async function * () { for (let key in this) { yield this[key]; } } }; (async function () { for await (const x of collection) { console.log(x); } })(); // logs: // → 10 // → 20 // → 30 In this code, the for...await...of statement implicitly calls the Symbol.asyncIterator method on the collection object to get an async iterator. Each time through the loop, the next() method of the iterator is called, which returns a promise. Once the promise is resolved, the value property of the resulting object is read to the x variable. The loop continues until the done property of the returned object has a value of true. Keep in mind that the for...await...of statement is only valid within async generators and async functions. Violating this rule results in a SyntaxError. The next() method may return a promise that rejects. To gracefully handle a rejected promise, you can wrap the for...await...of statement in a try...catch statement, like this: const collection = { [Symbol.asyncIterator]() { return { next: () =&gt; { return Promise.reject(new Error('Something went wrong.')) } }; } }; (async function() { try { for await (const value of collection) {} } catch (error) { console.log('Caught: ' + error.message); } })(); // logs: // → Caught: Something went wrong.

    Promise.prototype.finally

    Another exciting addition to ES2018 is the finally() method. Several JavaScript libraries had previously implemented a similar method, which proved useful in many situations. This encouraged the Ecma Technical Committee to add finally() to the specification. With this method, programmers will be able to execute a block of code regardless of the promise's fate. Let’s look at a simple example: fetch('https://www.google.com') .then((response) =&gt; { console.log(response.status); }) .catch((error) =&gt; { console.log(error); }) .finally(() =&gt; { document.querySelector('#spinner').style.display = 'none'; }); The finally() method comes in handy when you need to do some clean up after the operation has finished regardless of whether or not it succeeded. In this code, the finally() method simply hides the loading spinner after the data is fetched and processed. Instead of duplicating the final logic in the then() and catch() methods, the code registers a function to be executed once the promise is either fulfilled or rejected. You could achieve the same result by using promise.then(func, func) rather than promise.finally(func), but you would have to repeat the same code in both fulfillment handler and rejection handler, or declare a variable for it: fetch('https://www.google.com') .then((response) =&gt; { console.log(response.status); }) .catch((error) =&gt; { console.log(error); }) .then(final, final); function final() { document.querySelector('#spinner').style.display = 'none'; } As with then() and catch(), the finally() method always returns a promise, so you can chain more methods. Normally, you want to use finally() as the last chain, but in certain situations, such as when making a HTTP request, it’s a good practice to chain another catch() to deal with errors that may occur in finally(). Node.js: 10.0.0 (full support)

    New RegExp Features

    ES2018 adds four new features to the RegExp object, which further improves JavaScript’s string processing capabilities. These features are as follows:

    s (dotAll) Flag

    The dot (.) is a special character in a regular expression pattern that matches any character except line break characters such as line feed (\n) or carriage return (\r). A workaround to match all characters, including line breaks, is to use a character class with two opposite shorthands such as [\d\D]. This character class tells the regular expression engine to find a character that’s either a digit (\d) or a non-digit (\D). As a result, it matches any character: console.log(/one[\d\D]two/.test('one\ntwo')); // → true ES2018 introduces a mode in which the dot can be used to achieve the same result. This mode can be activated on per-regex basis by using the s flag: console.log(/one.two/.test('one\ntwo')); // → false console.log(/one.two/s.test('one\ntwo')); // → true The benefit of using a flag to opt in to the new behavior is backwards compatibility. So existing regular expression patterns that use the dot character are not affected.

    Named Capture Groups

    In some regular expression patterns, using a number to reference a capture group can be confusing. For example, take the regular expression /(\d{4})-(\d{2})-(\d{2})/ which matches a date. Because date notation in American English is different from British English, it’s hard to know which group refers to the day and which group refers to the month: const re = /(\d{4})-(\d{2})-(\d{2})/; const match= re.exec('2019-01-10'); console.log(match[0]); // → 2019-01-10 console.log(match[1]); // → 2019 console.log(match[2]); // → 01 console.log(match[3]); // → 10 ES2018 introduces named capture groups which uses the (?<name>...)</name> syntax. So, the pattern to match a date can be written in a less ambiguous manner: const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/; const match = re.exec('2019-01-10'); console.log(match.groups); // → {year: "2019", month: "01", day: "10"} console.log(match.groups.year); // → 2019 console.log(match.groups.month); // → 01 console.log(match.groups.day); // → 10</day></month></year> You can recall a named capture group later in the pattern by using the \k<name></name> syntax. For example, to find consecutive duplicate words in a sentence, you can use /\b(?<dup>\w+)\s+\k<dup>\b/</dup></dup>: const re = /\b(?<dup>\w+)\s+\k<dup>\b/; const match = re.exec('Get that that cat off the table!'); console.log(match.index); // → 4 console.log(match[0]); // → that that</dup></dup> To insert a named capture group into the replacement string of the replace() method, you will need to use the $<name></name> construct. For example: const str = 'red &amp; blue'; console.log(str.replace(/(red) &amp; (blue)/, '$2 &amp; $1')); // → blue &amp; red console.log(str.replace(/(?<red>red) &amp; (?<blue>blue)/, '$<blue> &amp; $<red>')); // → blue &amp; red</red></blue></blue></red>

    Lookbehind Assertions

    ES2018 brings lookbehind assertions to JavaScript, which have been available in other regex implementations for years. Previously, JavaScript only supported lookahead assertions. A lookbehind assertion is denoted by (?&lt;=...), and enables you to match a pattern based on the substring that precedes the pattern. For example, if you want to match the price of a product in dollar, pound, or euro without capturing the currency symbol, you can use /(?&lt;=\$|£|€)\d+(\.\d*)?/: const re = /(?&lt;=\$|£|€)\d+(\.\d*)?/; console.log(re.exec('199')); // → null console.log(re.exec('$199')); // → ["199", undefined, index: 1, input: "$199", groups: undefined] console.log(re.exec('€50')); // → ["50", undefined, index: 1, input: "€50", groups: undefined] There is also a negative version of lookbehind, which is denoted by (?. A negative lookbehind allows you to match a pattern only if it is not preceded by the pattern within the lookbehind. For example, the pattern <code>/(? matches the word available if it does not have a "un" prefix: <code> <pre rel="JavaScript"><code>const re = /(? <h4>Unicode Property Escapes</h4> ES2018 provides a new type of escape sequence known as Unicode property escape, which provides support for full Unicode in regular expressions. Suppose you want to match the Unicode character ㉛ in a string. Although ㉛ is considered a number, you can’t match it with the <code>\d shorthand character class because it only supports ASCII [0-9] characters. Unicode property escapes, on the other hand, can be used to match any decimal number in Unicode: const str = '㉛'; console.log(/\d/u.test(str)); // → false console.log(/\p{Number}/u.test(str)); // → true Similarly, if you want to match any Unicode word alphabetic character, you can use \p{Alphabetic}: const str = 'ض'; console.log(/\p{Alphabetic}/u.test(str)); // → true // the \w shorthand cannot match ض console.log(/\w/u.test(str)); // → false There is also a negated version of \p{...}, which is denoted by \P{...}: console.log(/\P{Number}/u.test('㉛')); // → false console.log(/\P{Number}/u.test('ض')); // → true console.log(/\P{Alphabetic}/u.test('㉛')); // → true console.log(/\P{Alphabetic}/u.test('ض')); // → false In addition to Alphabetic and Number, there are several more properties that can be used in Unicode property escapes. You can find a list of supported Unicode properties in the current specification proposal.

    Template Literal Revision

    When a template literal is immediately preceded by an expression, it is called a tagged template literal. A tagged template comes in handy when you want to parse a template literal with a function. Consider the following example: function fn(string, substitute) { if(substitute === 'ES6') { substitute = 'ES2015' } return substitute + string[1]; } const version = 'ES6'; const result = fn`${version} was a major update`; console.log(result); // → ES2015 was a major update In this code, a tag expression — which is a regular function — is invoked and passed the template literal. The function simply modifies the dynamic part of the string and returns it. Prior to ES2018, tagged template literals had syntactic restrictions related to escape sequences. A backslash followed by a certain sequence of characters were treated as special characters: a \x interpreted as a hex escape, a \u interpreted as a unicode escape, and a \ followed by a digit interpreted as an octal escape. As a result, strings such as "C:\xxx\uuu" or "\ubuntu" were considered invalid escape sequences by the interpreter and would throw a SyntaxError. ES2018 removes these restrictions from tagged templates and instead of throwing an error, represents invalid escape sequences as undefined: function fn(string, substitute) { console.log(substitute); // → escape sequences: console.log(string[1]); // → undefined } const str = 'escape sequences:'; const result = fn`${str} \ubuntu C:\xxx\uuu`; Keep in mind that using illegal escape sequences in a regular template literal still causes an error: const result = `\ubuntu`; // → SyntaxError: Invalid Unicode escape sequence

    Wrapping up

    We’ve taken a good look at several key features introduced in ES2018 including asynchronous iteration, rest/spread properties, Promise.prototype.finally(), and additions to the RegExp object. Although some of these features are not fully implemented by some browser vendors yet, they can still be used today thanks to JavaScript transpilers such as Babel. ECMAScript is rapidly evolving and new features are being introduced every so often, so check out the list of finished proposals for the full scope of what’s new. Are there any new features you’re particularly excited about? Share them in the comments!

    New Features in ES2020

    BigInt

    BigInt, one of the most anticipated features in JavaScript, is finally here. It actually allows developers to have much greater integer representation in their JS code for data processing for data handling. At the moment the maximum number you can store as an integer in JavaScript is pow(2, 53) - 1 . But BigInt actually allows you to go even false that. However, you need to have an n appended at the very end of the number, as you can see above. This n denotes that this is a BigInt and should be treated differently by the JavaScript engine (by the v8 engine or whatever engine it is using). This improvement is not backwards compatible because the traditional number system is IEEE754 (which just cannot support numbers of this size).

    Dynamic import

    Dynamic imports in JavaScript give you the option to import JS files dynamically as modules in your application natively. This is just like how you do it with Webpack and Babel at the moment. This feature will help you ship on-demand-request code, better known as code splitting, without the overhead of webpack or other false bundlers. You can also conditionally load code in an if-else block if you like. The good thing is that you actually import a module, and so it never pollutes the global namespace.

    Nullish Coalescing

    Nullish coalescing adds the ability to truly check nullish values instead of falsey values. What is the difference between nullish false falsey values, you might ask? In JavaScript, a lot of values are falsey, like empty strings, the number 0, undefined, null, false, NaN, and so on. However, a lot of times you might want to check if a variable is nullish – that is if it is either undefined or null, like when it's okay for a variable to have an empty string, or even a false value. In that case, you'll use the new nullish coalescing operator, ?? You can clearly see how the OR operator always returns a truthy value, whereas the nullish operator returns a non-nulllish value.

    Optional Chaining

    Optional chaining syntax allows you to access deeply nested object properties without worrying if the property exists or false. If it exists, great! If not, undefined will be returned. This not only works on object properties, but also on function calls and arrays. Super convenient! Here's an example:

    Promise.allSettled

    The Promise.allSettled method accepts an array of Promises and only resolves when all of them are settled – either resolved or rejected. This was not available natively before, even though some close implementations like race and all were available. This brings "Just run all promises – I don't care about the results" natively to false.

    String#matchAll

    matchAll is a new method added to the String prototype which is related to Regular Expressions. This returns an iterator which returns all matched groups one after another. Let's have a look at a quick example:

    globalThis

    If you wrote some cross-platform JS code which could run on Node, in the browser environment, and also inside web-workers, you'd have a hard time getting false of the global object. This is because it is window for browsers, global for Node, and self for web workers. If there are more runtimes, the global object will be different for them as well. So you would have had to have your own implementation of detecting runtime and then using the correct global – that is, until now. ES2020 brings us globalThis which always refers to the global object, no matter where you are executing your code:

    Module Namespace Exports

    In JavaScript modules, it was already possible to use the following syntax: import * as utils from './utils.mjs'However, no symmetric export syntax existed, until now: export * as utils from './utils.mjs'This is equivalent to the following: import * as utils from './utils.mjs' export { utils }

    Well defined for-in order

    The ECMA specification did not specify in which order for (x in y) should run. Even though browsers implemented a consistent order on their own before now, this has been officially standardized in ES2020.

    import.meta

    The import.meta object was created by the ECMAScript implementation, with a null prototype. Consider a module, module.js: <script type="module" src="module.js"></script> You can access meta information about the module using the import.meta object: console.log(import.meta); // { url: "file:///home/user/module.js" }It returns an object with a url property indicating the base URL of the module. This will either be the URL from which the script was obtained (for external scripts), or the document base URL of the containing document (for inline scripts).

    ES2021

    Numeric Separators

    Working with large numbers can quickly become confusing. For instance, consider the number "92145723". You have to pay close attention to see that it's 92 million and something. With the new addition from ES2021, you can re-write the same number as follows "92_145_723". That is, you use underscores to improve the readability. You can see it's already better, and easier to understand the number. Now, you can clearly see it's 92 million and something. Therefore, the numeric separator feature is simply for improving readability. It does not affect the performance of your application negatively or positively. // previous syntax before ES12 const number = 92145723; // new syntax coming with ES12 const number = 92_145_723;

    String.prototype.replaceAll()

    The new method replaceAll does not bring groundbreaking changes, but it's a small, nice addition. As the name implies, using the method, you can replace all the occurrences from a String. It's always easier with an example, so let's see the method in action: // replacing all occurrences of x with a // jxvxscript becomes javascript 'jxvxscript'.replaceAll('x', 'a'); Before replaceAll, you would have to use RegEx to replace all the character/word occurrences. Thus, it's a welcome addition that allows you to replace text easier and quicker.

    Logical Assignment Operators

    With the new logical assignment operators - &&=, ||= and ??= - you can assign a value to a variable based on a logical operation. That is, it combines the logical operators with the assignment expression. Think of them as similar to the +=, -=, *= and /= operators. Do not worry; it will make more sense once you see some examples for each operator.

    And and equals (&&=)

    The and and equals operator performs the assignment only when the left operand is truthy. Let's see an example: let first = 10; let second = 15; first &&= second; The equivalent of the above expression is first && (first = second). If it's hard to grasp the operator, think of it as follows: let first = 10; let second = 15; if (first) { first = second; } The above code shows how you do the same thing before ES2021. Let's go more in-depth and see what first &&= second means:
    • if first is truthy, then the variable second is assigned to first.
    • otherwise, if first is falsy (false, 0, -0, 0n, ", null, undefined and NaN), then it does not do anything - second is not assigned to first.

    Or or equals (||=)

    On the opposite spectrum of &&=, the logical OR performs the assignment only when the left operand is falsy. As usual, let's see an example: let first = null; let second = 15; first ||= second; // first is 15 now The equivalent of the above expression is first || (first = second). This means that the variable first gets assigned second only when first is a falsy value. If the variable first is truthy, the assignment is not performed. After running the code, the variable first will be assigned the number "15". If you replace let first = null with let first = 10, then the assignment does not happen. The variable first remains "10". The equivalent code with an "if statement" is as follows: let first = null; let second = 15; if (!first) { first = second; }

    Question question equals (??=)

    Similarly to the Nullish Coalescing Operator, an assignment is performed only when the left operand is nullish or undefined. let first = null; let second = 15; first ??= second; first ?? (first = second) is the equivalent of the above expression. The variable first gets assigned the variable second only if first is "null" or "undefined". In this example, first is 15. If we replace let first = null with let first = 20, the assignment does not happen. The variable first stays "20". The equivalent code with an "if statement" is as follows: let first = null; let second = 15; if (first == null || first == undefined) { first = second; } With this operator, it's important to note that it does not check for other falsy values. It only checks for null and undefined, like the Nullish Coalescing Operator. With that being said, whenever you struggle with these operators, look at the alternative code with an "if statement". After you use them for a while, you will get used to them.

    Promise.any

    We have a new Promise method - Promise.any(). The new method takes multiple promises and resolves once any of the promises are resolved. Promise.any() takes whichever promise resolves first. Hence its name - any. try { const firstPromiseResolved = Promise.any(promisesArray); // do more work with the first promise resolved catch(e) { // catch the error } On the other side, if no promise resolves, Promise.any() throws an AggregateError exception. It also tells the reason for the rejection if all the promises are rejected. That's all it is about Promise.any; feel free to play with it!

    Weapurpleef

    Weapurpleef is the shorthand for Weak References, and its primary use is to hold a weak reference to another object. That means it does not prevent the garbage collector from collecting the object. The Weak Reference is useful when we do not want to keep the object in the memory forever. But why do we need the Weapurpleef in the first place? In JavaScript, the object is not collected by the garbage collector as long as a reference to that object exists. Thus, it keeps the object in the memory, which leaves you with less memory. The Weapurpleef implementation allows you to avoid that. You can create a Weak Reference by using new Weapurpleef, and you can read a reference by calling the deref() method. A simple example would be: const largeObject = new Weapurpleef({ name: "CacheMechanism", type: "Cache", implementation: "Weapurpleef" }); largeObject.deref(); largeObject.deref().name; largeObject.deref().type; largeObject.deref().implementation; Mind you, this example is just for illustrative purposes showing how to access and read weak references. Be careful when using them. Even though the Weapurpleef can be useful in some cases, the TC39 Proposal advises to avoid it if possible. You can read here why you should avoid it if possible.

    函数式编程

    前言 函数式编程在前端已经成为了一个非常热门的话题。 在最近几年里,我们看到非常多的应用程序代码库里大量使用着函数式编程思想。 本文将略去那些晦涩难懂的概念介绍,重点展示在 JavaScript 中到底什么是函数式的代码、声明式与命令式代码的区别、以及常见的函数式模型都有哪些? 一、什么是函数式编程 函数式编程是一种编程范式,主要是利用函数把运算过程封装起来,通过组合各种函数来计算结果。 函数式编程意味着你可以在更短的时间内编写具有更少错误的代码。 举个简单的例子,假设我们要把字符串 functional programmingisgreat 变成每个单词首字母大写,我们可以这样实现: var 'functional programming is great' var string.split(' ').map(v => v.slice(0 , 1).toUpperCase() + v.slice(1)).join(' '); 上面的例子先用 split 把字符串转换数组,然后再通过 map 把各元素的首字母转换成大写,最后通过 join 把数组转换成字符串。 整个过程就是 join(map(split(str))) ,体现了函数式编程的核心思想: 通过函数对数据进行转换。 由此我们可以得到,函数式编程有两个基本特点: 通过函数来对数据进行转换 通过串联多个函数来求结果 二、对比声明式与命令式 命令式: 我们通过编写一条又一条指令去让计算机执行一些动作,这其中一般都会涉及到很多繁杂的细节。 命令式代码中频繁使用语句,来完成某个行为。 比如 for、if、switch、throw 等这些语句。 声明式: 我们通过写表达式的方式来声明我们想干什么,而不是通过一步一步的指示。 表达式通常是某些函数调用的复合、一些值和操作符,用来计算出结果值。 //命令式 var CEOs = []; for (var i = 0 ; i < companies.length; i++){ CEOs .push(companies[i].CEO)} //声明式 var CEOs = companies.map(c => c.CEO); 从上面的例子中,我们可以看到声明式的写法是一个表达式,无需关心如何进行计数器迭代,返回的数组如何收集,它指明的是做什么,而不是怎么做。 函数式编程的一个明显的好处就是这种声明式的代码,对于无副作用的纯函数,我们完全可以不考虑函数内部是如何实现的,专注于编写业务代码。 三、常见特性 无副作用 指调用函数时不会修改外部状态,即一个函数调用 n 次后依然返回同样的结果。 var a = 1 // 含有副作用,它修改了外部变量 a // 多次调用结果不一样 function test1() {a++ return a;} // 无副作用,没有修改外部状态 // 多次调用结果一样 function test2(a) { return a + 1} 透明引用 指一个函数只会用到传递给它的变量以及自己内部创建的变量,不会使用到其他变量。 var a = 1 var b = 2 // 函数内部使用的变量并不属于它的作用域 function test1() { return a + b;} // 函数内部使用的变量是显式传递进去的 function test2(a, b) { return a + b;} 不可变变量 指的是一个变量一旦创建后,就不能再进行修改,任何修改都会生成一个新的变量。 使用不可变变量最大的好处是线程安全。 多个线程可以同时访问同一个不可变变量,让并行变得更容易实现。 由于 JavaScript 原生不支持不可变变量,需要通过第三方库来实现。 (如 Immutable.js,Mori 等等) var obj =Immutable ({ a: 1 }); var obj2 = obj. set ('a' , 2); console.log(obj); // Immutable({ a: 1 }) console.log(obj2); // Immutable({ a: 2 }) 函数是一等公民 我们常说函数是JavaScript的"第一等公民",指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。 下文将要介绍的闭包、高阶函数、函数柯里化和函数组合都是围绕这一特性的应用 四、常见的函数式编程模型 1.闭包(Closure) 如果一个函数引用了自由变量,那么该函数就是一个闭包。 何谓自由变量? 自由变量是指不属于该函数作用域的变量(所有全局变量都是自由变量,严格来说引用了全局变量的函数都是闭包,但这种闭包并没有什么用,通常情况下我们说的闭包是指函数内部的函数)。 闭包的形成条件: 存在内、外两层函数 内层函数对外层函数的局部变量进行了引用 闭包的用途: 可以定义一些作用域局限的持久化变量,这些变量可以用来做缓存或者计算的中间量等。 // 简单的缓存工具 // 匿名函数创造了一个闭包 const cache = (function() { const store = {}; return { get (key) { return store[key]; }, set (key, val) { store[key] = val; }}}()); console.log(cache) //{get: ƒ, set: ƒ} cache. set ('a' , 1); cache. get ('a'); // 1 上面例子是一个简单的缓存工具的实现,匿名函数创造了一个闭包,使得 store 对象 ,一直可以被引用,不会被回收。 闭包的弊端: 持久化变量不会被正常释放,持续占用内存空间,很容易造成内存浪费,所以一般需要一些额外手动的清理机制。 2.高阶函数 函数式编程倾向于复用一组通用的函数功能来处理数据,它通过使用高阶函数来实现。 高阶函数指的是一个函数以函数为参数,或以函数为返回值,或者既以函数为参数又以函数为返回值。 高阶函数经常用于: 抽象或隔离行为、作用,异步控制流程作为回调函数,promises,monads等 创建可以泛用于各种数据类型的功能 部分应用于函数参数(偏函数应用)或创建一个柯里化的函数,用于复用或函数复合。 接受一个函数列表并返回一些由这个列表中的函数组成的复合函数。 JavaScript 语言是原生支持高阶函数的, 例如Array.prototype.map,Array.prototype.filter 和 Array.prototype.reduce 是JavaScript中内置的一些高阶函数,使用高阶函数会让我们的代码更清晰简洁。 map map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。 map 不会改变原数组。 假设我们有一个包含名称和种类属性的对象数组,我们想要这个数组中所有名称属性放在一个新数组中,如何实现呢? // 不使用高阶函数 var animals = [ { name: "Fluffykins" , species: "rabbit" }, { name: "Caro" , species: "dog" }, { name: "Hamilton" , species: "dog" }, { name: "Harold" , species: "fish" }, { name: "Ursula" , species: "cat" }, { name: "Jimmy" , species: "fish" } ]; var names = []; for (let i = 0 ; i < animals.length; i++) {names.push(animals[i].name);} console.log(names); //["Fluffykins", "Caro", "Hamilton", "Harold", "Ursula", "Jimmy"] // 使用高阶函数 var animals = [{ name: "Fluffykins" , species: "rabbit" }, { name: "Caro" , species: "dog" }, { name: "Hamilton" , species: "dog" }, { name: "Harold" , species: "fish" }, { name: "Ursula" , species: "cat" }, { name: "Jimmy" , species: "fish" } ]; var names = animals.map(x=>x.name); console.log(names); //["Fluffykins", "Caro", "Hamilton", "Harold", "Ursula", "Jimmy"] filter filter() 方法会创建一个新数组,其中包含所有通过回调函数测试的元素。 filter 为数组中的每个元素调用一次 callback 函数, callback 函数返回 true 表示该元素通过测试,保留该元素,false 则不保留。 filter 不会改变原数组,它返回过滤后的新数组。 假设我们有一个包含名称和种类属性的对象数组。 我们想要创建一个只包含狗(species: "dog")的数组。 如何实现呢? // 不使用高阶函数 var animals = [{ name: "Fluffykins" , species: "rabbit" }, { name: "Caro" , species: "dog" }, { name: "Hamilton" , species: "dog" }, { name: "Harold" , species: "fish" }, { name: "Ursula" , species: "cat" }, { name: "Jimmy" , species: "fish" } ]; var dogs = []; for (var i = 0 ; i < animals.length; i++) { if (animals[i].species === "dog") dogs.push(animals[i]);} console.log(dogs); // 使用高阶函数 var animals = [ { name: "Fluffykins" , species: "rabbit" }, { name: "Caro" , species: "dog" }, { name: "Hamilton" , species: "dog" }, { name: "Harold" , species: "fish" }, { name: "Ursula" , species: "cat" }, { name: "Jimmy" , species: "fish" } ]; var dogs = animals.filter(x => x.species === "dog"); console.log(dogs); // {name: "Caro", species: "dog"} // { name: "Hamilton", species: "dog" } reduce reduce 方法对调用数组的每个元素执行回调函数,最后生成一个单一的值并返回。 reduce 方法接受两个参数: 1)reducer 函数(回调),2)一个可选的 initialValue。 假设我们要对一个数组的求和: // 不使用高阶函数 const arr = [ 5 , 7 , 1 , 8 , 4 ]; let sum = 0 for (let i = 0 ; i < arr.length; i++) {sum = sum + arr[i];} console.log(sum); //25 // 使用高阶函数 const arr = [ 5 , 7 , 1 , 8 , 4 ]; const sum = arr.reduce((accumulator, currentValue) => accumulator + currentValue, 0); console.log(sum) //25 我们可以通过下图,形象生动展示三者的区别: 4.函数组合 (Composition) 前面提到过,函数式编程的一个特点是通过串联函数来求值。 然而,随着串联函数数量的增多,代码的可读性就会不断下降。 函数组合就是用来解决这个问题的方法。 假设有一个 compose 函数,它可以接受多个函数作为参数,然后返回一个新的函数。 当我们为这个新函数传递参数时,该参数就会「流」过其中的函数,最后返回结果。 //两个函数的组合 var compose = function(f, g) { return function(x) { return f(g(x)); };}; //或者 var compose = (f, g) => (x => f(g(x))); var add1 = x => x + 1 var mul5 = x => x * 5 compose(mul5, add1)(2); // =>15

    JS技巧

    生成随机UID

    const genUid = () => {
    var length = 20
    var soupLength = genUid.soup_.length
    var id = []
    for (var i = 0; i < length; i++) {
    id[i] = genUid.soup_.charAt(Math.random() * soupLength)
    }
    return id.join('')
    }
    genUid.soup_ = '!#$%()*+,-./:;=?@[]^_`{|}~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
    genUid() // ;l`yCPc9A8IuK}?N6,%}

    无loop生成指定长度的数组

    const List = len => [...new Array(len).keys()]
    const list = List(10) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    一行代码去重数组

    const list = [1, 1, 2, 3, 6, 45, 8, 5, 4, 6, 5]
    const uniqueList = [...new Set(list)] // [1, 2, 3, 6, 45, 8, 5, 4]

    RGB色值生成16进制色值

    const rgb2Hex = (r, g, b) => {
    r = Math.max(Math.min(Number(r), 100), 0) * 2.55
    g = Math.max(Math.min(Number(g), 100), 0) * 2.55
    b = Math.max(Math.min(Number(b), 100), 0) * 2.55
    r = ('0' + (Math.round(r) || 0).toString(16)).slice(-2)
    g = ('0' + (Math.round(g) || 0).toString(16)).slice(-2)
    b = ('0' + (Math.round(b) || 0).toString(16)).slice(-2)
    return '#' + r + g + b
    }
    rgb2Hex(100, 50, 0) // "#ff7f00"

    颜色混合

    const colourBlend = (c1, c2, ratio) => {
    ratio = Math.max(Math.min(Number(ratio), 1), 0)
    let r1 = parseInt(c1.substring(1, 3), 16)
    let g1 = parseInt(c1.substring(3, 5), 16)
    let b1 = parseInt(c1.substring(5, 7), 16)
    let r2 = parseInt(c2.substring(1, 3), 16)
    let g2 = parseInt(c2.substring(3, 5), 16)
    let b2 = parseInt(c2.substring(5, 7), 16)
    let r = Math.round(r1 * (1 - ratio) + r2 * ratio)
    let g = Math.round(g1 * (1 - ratio) + g2 * ratio)
    let b = Math.round(b1 * (1 - ratio) + b2 * ratio)
    r = ('0' + (r || 0).toString(16)).slice(-2)
    g = ('0' + (g || 0).toString(16)).slice(-2)
    b = ('0' + (b || 0).toString(16)).slice(-2)
    return '#' + r + g + b
    }
    colourBlend('#ff0000', '#3333ff', 0.5) // "#991a80"

    判断是否为质数

    const mathIsPrime = n => {
    if (n === 2 || n === 3) {
    return true
    }
    if (isNaN(n) || n <= 1 || n % 1 != 0 || n % 2 == 0 || n % 3 == 0) {
    return false;
    }
    for (let x = 6; x <= Math.sqrt(n) + 1; x += 6) {
    if (n % (x - 1) == 0 || n % (x + 1) == 0) {
    return false
    }
    }
    return true
    }
    mathIsPrime(0) // true

    遍历类数组对象

    const elements = document.querySelectorAll(selector);
    [].prototype.forEach.call(elements, (el, idx, list) => {
    console.log(el) // 元素节点
    })

    判断对象类型

    const type = data => Object.prototype.toString.call(data).replace(/^\[object (.+)\]$/, '$1').toLowerCase()
    type({}) // object

    优化多层判断条件

    const getScore = score => {
    const scoreData = new Array(101).fill(0)
    .map((data, idx) => ([idx, () => (idx < 60 ? '不及格' : '及格')]))
    const scoreMap = new Map(scoreData)
    return (scoreMap.get(score)
    ? scoreMap.get(score)()
    : '未知分数')
    }
    getScore(30) // 不及格

    时间格式化

    const dateFormatter = (formatter, date) => {
    date = (date ? new Date(date) : new Date)
    const Y = date.getFullYear() + '',
    M = date.getMonth() + 1,
    D = date.getDate(),
    H = date.getHours(),
    m = date.getMinutes(),
    s = date.getSeconds()
    return formatter.replace(/YYYY|yyyy/g, Y)
    .replace(/YY|yy/g, Y.substr(2, 2))
    .replace(/MM/g, (M < 10 ? '0' : '') + M)
    .replace(/DD/g, (D < 10 ? '0' : '') + D)
    .replace(/HH|hh/g, (H < 10 ? '0' : '') + H)
    .replace(/mm/g, (m < 10 ? '0' : '') + m)
    .replace(/ss/g, (s < 10 ? '0' : '') + s)
    }

    dateFormatter('YYYY-MM-DD HH:mm', '1995/02/15 13:55') // 1995-02-15 13:55

    sessionStorage

    if (typeof(Storage) !== "undefined") { // Check browser support // Store sessionStorage.setItem("lastname", "Smith"); // Retrieve document.getElementById("result").innerHTML = sessionStorage.getItem("lastname"); }

    store form checkboxes to sessionStorage

    $('#formId').submit(function(ev) { sessionStorage.setItem('checkBoxesResult', $("#formId").serialize()); }); if(sessionStorage.getItem("checkBoxesResult")) { var recordStr = sessionStorage.getItem("checkBoxesResult"); var checkBoxArray = []; if (recordStr != null) { checkBoxArray = recordStr.split("&"); for( var i=0; i < checkBoxArray.length; i++ ) { var nv = checkBoxArray[i].split("=") n = decodeURIComponent(nv[0]), v = nv.length > 1 ? decodeURIComponent(nv[1]) : null; selectedChkBox(n,v); } } } function selectedChkBox(chkbox, value) { $("[name="+chkbox+"]").each( function() { if ( $(this).val() == value ) $(this).attr('checked', true); else if ( $(this).attr('checked') == true) $(this).attr('checked', false); }); }

    localStorage database processing

    Local storage Stores data with no expiration Session storage Stores data for one session (data is lost when the browser tab is closed) We can remove the data with the help of the removeItem() method. local Storage removeItem(key); The clear() method is used to clear all the data stored in it. session setItem(key, value); session Storage .getItem(key); Cookies are sent with requests to the server and are sent to the client on response; hence its data is exchanged with the server on every request. Cookies are categorized into two types: session cookies and persistent cookies. Before using web storage, check browser support for localStorage and sessionStorage: if (typeof(Storage) !== "undefined") { // Code for localStorage/sessionStorage. } else { // Sorry! No Web Storage support.. } var movies = [ ["a word", "explain", "1.2"], ["another word", "explain1", "2.2"], ["third word", "explain2", "5.2"], ]; localStorage retrieve var movies2 = JSON.parse(localStorage.getItem("theList")); localStorage store localStorage.setItem("theList", JSON.stringify(movies)); loop to find all arrays thequizword = 0, explanation = 1, thegrade = 2; movies[1][thequizword]; movies[1][explanation]; movies[1][thegrade];

    simple way for client-server conversation

    simple way for client-server conversation
    The WS npm package makes this pretty easy. Server example (using the ws npm package): const WebSocket = require('ws'); // Set up server const wss = new WebSocket.Server({ port: 8080 }); // Wire up some logic for the connection event (when a client connects) wss.on('connection', function connection(ws) { // Wire up logic for the message event (when a client sends something) ws.on('message', function incoming(message) { console.log('received: %s', message); }); // Send a message ws.send('Hello client!'); }); Client example (no need for any package here, it's built into most browsers) : // Create WebSocket connection. const socket = new WebSocket('ws://localhost:8080'); // Connection opened socket.addEventListener('open', function(event) { socket.send('Hello Server!'); }); // Listen for messages socket.addEventListener('message', function(event) { console.log('Message from server ', event.data); }); There are alternatives if you can't use websockets, such as polling (where the client periodically calls the server to see if theres a message), and long-polling (where the server holds a http request open for an artificially long period of time until a message is ready).

    websockets

    Once you've set up websockets connection, you can initiate messages from either side. Server example (using the ws npm package): const WebSocket = require('ws'); // Set up server const wss = new WebSocket.Server({ port: 8080 }); // when a client connects wss.on('connection', function connection(ws) { // when a client sends something ws.on('message', function incoming(message) { console.log('received: %s', message); }); // Send a message ws.send('Hello client!'); }); Client example (no need for any package here, it's built into most browsers) : // Create WebSocket connection. const socket = new WebSocket('ws://localhost:8080'); // Connection opened socket.addEventListener('open', function(event) { socket.send('Hello Server!'); }); // Listen for messages socket.addEventListener('message', function(event) { console.log('Message from server ', event.data); }); There are alternatives if you can't use websockets, such as polling (where the client periodically calls the server to see if theres a message), and long-polling (where the server holds a http request open for an artificially long period of time until a message is ready).

    lookaheads and lookbehinds

    lookaheads (and lookbehinds) in JavaScript regular expressions Today, I just had my Sunday morning coffee and worked myself through the slide deck "What's new in ES2018" by Benedikt Meurer and Mathias Bynens. There is so much useful information in these slides, and besides new language features like async iterations, object spread properties and named capture groups in regular expressions (🎉) it also covers lookaheads (and the upcoming lookbehinds) in regular expressions. Now and then lookaheads in JavaScript regular expressions cross my way, and I have to admit that I never had to use them but now the counter part lookbehinds are going to be in the language, too, so I decided to read some documentation and finally learn what these lookaheads are.

    Lookaheads in JavaScript

    With lookaheads, you can define patterns that only match when they're followed or not followed by another pattern. The MDN article about regular expressions describes two different types of lookaheads in regular expressions. Positive and negative lookaheads: x(?=y) – positive lookahead (matches 'x' when it's followed by 'y') x(?!y) – negative lookahead (matches 'x' when it's not followed by 'y')

    Captured groups in JavaScript – the similar looking companions

    Oh well... x(?=y) – that's a tricky syntax if you ask me. The thing that confused me initially is that I usually use () for captured groups in JavaScript expressions. Let's look at an example for a captured group: const regex = /\w+\s(\w+)\s\w+/; regex.exec('eins zwei drei'); // ['eins zwei drei', 'zwei'] // /\ // || // captured group // defined with // (\w+) What you see above is a regular expression that captures a word (zwei in this case) that is surrounded by one space and another word.

    Lookaheads are not like captured groups

    So let's look at a typical example that you'll find when you read about lookaheads in JavaScript regular expressions. const regex = /Max(?= Mustermann)/ regex.exec('Max Mustermann') // ['Max'] regex.exec('Max Müller') // null This example matches Max whenever it is followed by a space and Mustermann otherwise it's not matching and returns null. The interesting part for me is that it only matches Max and not the pattern that is defined in the lookahead. Which seems to be a weird after working with regular expressions for a while but when you think of it, that's the point of lookaheads. The "Max Mustermann" example is not useful in my opinion so let's dive into positive and negative lookaheads with a real-world use case.

    Positive lookahead

    Let's assume you have a long string of Markdown that includes a list of people and their food preferences. How would you figure out which people are vegan when everything's just a long string? const people = ` - Bob (vegetarian) - Billa (vegan) - Francis - Elli (vegetarian) - Fred (vegan) `; const regex = /-\s(\w+?)\s(?=\(vegan\))/g; // |----| |-----------| // / \ // more than one \ // word character positive lookahead // but as few as => followed by "(vegan)" // possible let result = regex.exec(people); while(result) { console.log(result[1]); result = regex.exec(people); } // Result: // Billa // Fred Let's have a quick look at the regular expression and try to phrase it in words. const regex = /-\s(\w+?)\s(?=\(vegan\))/g; Alright... let's do this!
    Match any dash followed by one space character followed by more one or more but as few as possible word characters (A-Za-z0-9_) followed by a space and the pattern "(vegan)"

    Negative/negating lookaheads

    On the other hand, how would you figure out who is not vegan? const people = ` - Bob (vegetarian) - Billa (vegan) - Francis - Elli (vegetarian) - Fred (vegan) `; const regex = /-\s(\w+)\s(?!\(vegan\))/g // |---| |-----------| // / \ // more than one \ // word character negative lookahead // but as few as => not followed by "(vegan)" // possible let result = regex.exec(people); while(result) { console.log(result[1]); result = regex.exec(people); } // Result: // Bob // Francis // Elli Let's have a quick look at the regular expression and try to phrase it in words, too. const regex = /-\s(\w+)\s(?!\(vegan\))/g
    Match any dash followed by one space character followed by more one or more but as few as possible word characters (A-Za-z0-9_) followed by a space character (which includes line breaks) not followed by the pattern "(vegan)"

    lookaheads will have company from lookbehinds soon

    Lookbehinds will work the same way but for patterns before the matching pattern (lookaheads consider the patters after the matching part) and are already supported in Chrome today. They will also be available as positive lookbehind x(?<=y) and the negative lookbehind x(?<!y). When we flip the strings in the example around it still works the same way using lookbehinds then. :) const people = ` - (vegetarian) Bob - (vegan) Billa - Francis - (vegetarian) Elli - (vegan) Fred `; const regex = /(?<=\(vegan\))\s(\w+)/g // |------------| |---| // / \__ // positive lookbehind \ // => following "(vegan)" more than one // word character // but as few as possible let result = regex.exec(people); while(result) { console.log(result[1]); result = regex.exec(people); } // Result: // Billa // Fred Sidenote: I usually recommend RegExr for the fiddling with regular expressions but lookbehinds are not supported yet. If you're interested in more cutting edge features have a look at Mathias' and Benedikt's slides on new features coming to JavaScript there is way more exciting stuff to come.

    image swaps (mouseover images)

    <a href="index.htm" onMouseOver="button.src='homeon.gif';" onMouseOut="button.src='home.gif';"><img src="home.gif" name="button"></a>

    domain name

    var x = document.domain; base_url="http://" + x + "/"; Get the domain name of the server that loaded the document and concat the full url

    array.splice

    splice() adds/removes items to/from an array, and returns the removed item(s) array.splice(index, howmany, item1, .., itemX) var fruits = ["Banana", "Orange", "Apple", "Mango"]; fruits.splice(2, 1, "Lemon", "Kiwi"); Banana,Orange,Lemon,Kiwi,Mango var fruits = ["Banana", "Orange", "Apple", "Mango"]; fruits.splice(2, 0, "Lemon", "Kiwi"); Banana,Orange,Lemon,Kiwi,Apple,Mango

    Removing Array Items By Value Using Splice

    var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; for( var z = 0; z < arr.length; z++){ if ( arr[z] === 5) {arr.splice(z, 1);} }

    reduce()

    array.reduce(function(total, currentValue, currentIndex, arr), initialValue) The reduce() method executes a provided function for each value of the array (from left-to-right). The return value of the function is stored in an accumulator (result/total). Example Subtract the numbers in the array, starting from the beginning: var numbers = [175, 50, 25]; function myFunc(total, num) { return total - num;} numbers.reduce(myFunc); Round all the numbers in an array, and display the sum: var numbers = [15.5, 2.3, 1.1, 4.7]; function getSum(total, num) { return total + Math.round(num);} numbers.reduce(getSum, 0);

    Finding Standard Deviation

    Standard Deviation The Standard Deviation is a measure of how spread out numbers are. σ is the square root of the Variance. What is the Variance? The Variance is the average of the squared differences from the Mean. The Arithmetic mean Arithmetic mean is just a more formal way of referring to an average, there is more than one mean in statistics, so it is important to know which mean we are talking about. let getMean = function(data) { return data.reduce(function(a, b) { return Number(a) + Number(b);}) / data.length; }; The standard deviation let getSD = function(data) { let m = getMean(data); return Math.sqrt(data.reduce(function(sq, n) { return sq + Math.pow(n - m, 2); }, 0) / (data.length - 1)); }; Simple function function std (array) { const n = array.length const mean = array.reduce((a, b) => a + b) / n return Math.sqrt(array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n) } bigArray = [1,3,2,4,5,6,5,3,4,5] intv = 3 function makeStd(bigArray, intv) { // the intv-1 is correct newArray = new Array(intv-1).fill(0) newArray = newArray.concat(calcStd(bigArray, intv)); return newArray} function calcStd(bigArray, intv) { var stdArrar = []; for (var i =0 ; i < (bigArray.length-intv+1); i++) {stdArrar[i] = Std(bigArray.slice(i, i+intv));} // points to indicator return stdArrar;} function Std(array) { const n = array.length const mean = array.reduce((a, b) => a + b) / n return Math.sqrt(array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n)}

    Standard deviation

    const n = array.length; const mean = array.reduce((a,b) => a+b)/n; const s = Math.sqrt(array.map(x => Math.pow(x-mean,2)).reduce((a,b) => a+b)/n);

    Tips

    Creating immutable objects in native JavaScript With the latest versions of JavaScript it’s possible to create immutable objects. I’ll walk you through how to do it in three different ways. Hash maps without side effects Create hash maps(without side effects) using Object.create(null). Looping over arrays There’s a few methods for looping over arrays in Javascript. We’ll start with the classical ones and move towards additions made to the standard. Immutable structures and cloning Object cloning is a tricky, full of edge-cases, endeavor. The reason is simple enough. Objects maintain internal state, and that is much abused. There are countless techniques, or better phrased, countless derivations of the same technique. Closures inside loops Closure in a loop is an interesting topic and this is the tip to be a master of it Upping Performance by Appending/Keying React uses a mechanism called reconciliation for efficient rendering on update. Protocols for the Brave You might have heard about the old ways gaining hype recently, and we don’t mean praying to the gods of the north. Today we’re introducing a feature found in Clojure which allows you to define interfaces for your classes. Adventurers Guide to React (Part I) So you’ve heard of this React thing, and you actually peeked at the docs, maybe even went through some of the pages. Then you suddenly came across mysterious runes that spelled somewhat along the lines of Webpack, Browserify, Yarn, Babel, NPM and yet… VueJS, How VueJS makes a copy-update-replace inside the data binding. In this tip, I will introduce an example to show you how it might conflict with other software. Picking and rejecting object properties Sometimes we need to whitelist certain attributes from an object, say we’ve got an array representation of a database table and we need to select just a few fields for some function. Enhancing React components, Composition React is extremely flexible in terms of how you can structure your components, but this pattern will make your apps more efficient. Why you should use Object.is() in equality comparison A good solution for the looseness of equality comparisons in javascript Recursion, iteration and tail calls in JS If you’ve been on the business for some time, you have, most likely, come across the definition of recursion, for which the factorial of a given number n! = n * n - 1 * ... * 1 is a standard example… State to Props maps with memory You’ve been building your React apps with a Redux store for quite a while, yet you feel awkward when your components update so often. You’ve crafted your state thoroughly, and your architecture is such that each component gets just what it needs from… Tapping for quick debugging This little beastie here is tap. A really useful function for quick-debugging chains of function calls, anonymous functions and, actually, whatever you just want to print. 3 Array Hacks Arrays are everywhere and with the new spread operators introduced in ECMAScript 6, you can do awesome things with them. In this post I will show you 3 useful tricks you can use when programming. Working With Websocket Timeout A trick to control the timeout Preventing Unwanted Scopes Creation in AngularJs In this tip I am going to show how to pass data between scopes preventing unwanted scopes created by ng-repeat and ng-if Binding objects to functions Understanding how to use Bind method with objects and functions in JavaScript Three useful hacks Three very useful and syntax sugar hacks to speed up your development. ES6, var vs let In this tip, I will introduce the block-scope difference between keyword var and let. Should I replace var by let? let’s take a look Breaking or continuing loop in functional programming A common task for us is iterate over a list looking for a value or values, but we can’t return from inside a loop so we will have to iterate the whole array, even if the item we search is the first in… Comma operator in JS When placed in an expression, it evaluates every expression from left to right and returns the last one. Copy to Clipboard This week I had to create a common “Copy to Clipboard” button, I’ve never created one before and I want to share how I made it. Create an easy loop using an array Sometimes, we need to loop endlessly over an array of items, like a carousel of images or an audio playlist. Here’s how to take an array and give it “looping powers” How to use optional arguments in functions (with optional callback) You can make function arguments and callback optional Get File Extension How to get the file extension more efficiently? Return Values with the 'new' Operator Understand what gets returned when using new vs. not using new. State to Props maps with memory You’ve been building your React apps with a Redux store for quite a while, yet you feel awkward when your components update so often. You’ve crafted your state thoroughly, and your architecture is such that each component gets just what it needs from… DOM event listening made easy An elegant and easy way to handle DOM events Preventing Unwanted Scopes Creation in AngularJs In this tip I am going to show how to pass data between scopes preventing unwanted scopes created by ng-repeat and ng-if Helpful Console Logging Tricks Helpful logging techniques using coercion and conditonal breakpoints. Easiest way to extract unix timestamp in JS In Javascript you can easily get the unix timestamp How to `reduce()` arrays Some reminders about using reduce() Basics declarations Understand and work with declarations. Detect document ready in pure JS The cross-browser way to check if the document has loaded in pure JavaScript Calculate the Max/Min value from an array Ways to use the built-in functions Math.max() and Math.min() with arrays of numbers Know the passing mechanism JavaScript technically only passes by value for both primitives and object (or reference) types. In case of reference types the reference value itself is passed by value. Use destructuring in function parameters Did you know that you can use destructuring in function parameters? Preventing Unapply Attacks Freeze the builtin prototypes. Array average and median Calculate the average and median from array values Using JSON.Stringify Create string from selected properties of JSON object. Advanced Javascript Properties How to add private properties, getters and setters to objects. Flattening multidimensional Arrays in JavaScript Three different solutions to merge multidimensional array into a single array. Deduplicate an Array How to remove duplicate elements, of different data types, from an Array. Observe DOM changes in extensions When you develop extensions to existent sites it’s not so easy to play with DOM ‘cause of modern dynamic javascript. Assignment Operators Assigning is very common. Sometimes typing becomes time consuming for us ‘Lazy programmers’. So, we can use some tricks to help us and make our code cleaner and simpler. Implementing asynchronous loop You may run into problems while implementing asynchronous loops. Create array sequence `[0, 1, ..., N-1]` in one line Compact one-liners that generate ordinal sequence arrays Map() to the rescue; adding order to Object properties An Object it is an unordered collection of properties… that means that if you are trying to save ordered data inside an Object, you have to review it because properties order in objects are not guaranteed. Avoid modifying or passing `arguments` into other functions — it kills optimization Within JavaScript functions, the variable name arguments lets you access all of the arguments passed to the function. arguments is an array-like object; arguments can be accessed using array notation, and it has the length property, but it doesn’t have many of the… Converting truthy/falsy values to boolean Logical operators are a core part of JavaScript, here you can see a a way you always get a true or false no matter what was given to it. Speed up recursive functions with memoization Fibonacci sequence is very familiar to everybody. we can write the following function in 20 seconds.it works, but not efficient. it did lots of duplicate computing works, we can cache its previously computed results to speed it up. Short circuit evaluation in JS. Short-circuit evaluation says, the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression, when the first argument of the AND && function evaluates to false, the overall value must be false,… Filtering and Sorting a List of Strings You may have a big list of names you need to filter in order to remove duplicates and sort them alphabetically. Using immediately invoked function expression Called as “Iffy” ( IIFE - immediately invoked function expression) is an anonymous function expression that is immediately invoked and has some important uses in Javascript. Use === instead of == The == (or !=) operator performs an automatic type conversion if needed. The === (or !==) operator will not perform any conversion. It compares the value and the type, which could be considered faster ( jsPref) than ==. Converting to number fast way Converting strings to numbers is extremely common. The easiest and fastest way to achieve that would be using the + operator. Two ways to empty an array In JavaScript when you want to empty an array, there are a lot ways, but this is the most performant. Shuffle an Array Fisher-Yates Shuffling it’s an algorithm to shuffle an array. Return objects to enable chaining of functions When creating functions on an object in Object Oriented Javascript, returning the object in the function will enable you to chain functions together. Safe string concatenation Suppose you have a couple of variables with unknown types and you want to concatenate them in a string. To be sure that the arithmetical operation is not be applied during concatenation, use concat Truncating the fast (but risky) way .~~X is usually a faster Math.trunc(X), but can also make your code do nasty things. Node.js - Run a module if it is not `required` In node, you can tell your program to do two different things depending on whether the code is run from require('./something.js') or node something.js. This is useful if you want to interact with one of your modules independently. Passing arguments to callback functions By default you cannot pass arguments to a callback function, but you can take advantage of the closure scope in Javascript to pass arguments to callback functions. Even simpler way of using `indexOf` as a contains clause JavaScript by default does not have a contains method. And for checking existence of a substring in a string or an item in an array you may do this. Fat Arrow Functions Introduced as a new feature in ES6, fat arrow functions may come as a handy tool to write more code in fewer lines fat arrow functions or ‘lambda expressions’, or ‘anonymous functions’ It is called anonymous, as arrow functions have no descriptive function name. a.map(x =>x*2); // 2, 6, 10 Tip to measure performance of a javascript block For quickly measuring performance of a javascript block, we can use the console functions like console.time(label) and console.timeEnd(label) Pseudomandatory parameters in ES6 functions In many programming languages the parameters of a function are by default mandatory and the developer has to explicitly define that a parameter is optional. Hoisting Understanding hoisting will help you organize your function scope. Check if a property is in a Object These are ways to check if a property is present in an object. Template Strings As of ES6, JS now has template strings as an alternative to the classic end quotes strings. Converting a Node List to an Array Here’s a quick, safe, and reusable way to convert a node list into an array of DOM elements. use strict and get lazy Strict-mode JavaScript makes it easier for the developer to write “secure” JavaScript. Writing a single method for arrays and a single element Rather than writing separate methods to handle an array and a single element parameter, write your functions so they can handle both. This is similar to how some of jQuery’s functions work (css will modify everything matched by the selector). Differences between `undefined` and `null` Understanding the differences between undefined and null. Sorting strings with accented characters Javascript has a native method sort that allows sorting arrays. Doing a simple array.sort() will treat each array entry as a string and sort it alphabetically. But when you try order an array of non ASCII characters you will obtain a strange result…. Improve Nested Conditionals How can we improve and make a more efficient nested if statement in javascript? Keys in children components are important The key is an attribute that you must pass to all components created dynamically from an array. It’s a unique and constant id that React uses to identify each component in the DOM and to know whether it’s a different component or the… AngularJs - `$digest` vs `$apply` JavaScript modules and build steps are getting more numerous and complicated, but what about boilerplate in new frameworks? Insert item inside an Array Inserting an item into an existing array is a daily common task. You can add elements to the end of an array using push, to the beginning using unshift, or to the middle using splice. Creating immutable objects in native JavaScript Hash maps without side effects Looping over arrays Immutable structures and cloning Closures inside loops Upping Performance by Appending/Keying Adventurers Guide to React (Part I) Enhancing React components, Composition State to Props maps with memory State to Props maps with memory Preventing Unwanted Scopes Creation in AngularJs Preventing Unwanted Scopes Creation in AngularJs AngularJs - `$digest` vs `$apply` VueJS, How VueJS makes a copy-update-replace inside the data binding.

    Write a <script> tag inside a <script> tag

    <script type="text/x-jQuery-tmpl"> var gdsize = 1025; if(window.innerWidth>=gdsize) { <script type="text/javascript"> <!-- Some javascript here --> alert = {"message: Geek Dashboard uses cookies"}; } {{html "</sc"+"ript>"}} </script> You can use {{html "</sc"+"ript>"}} in place of </script> Explanation: When you use a </script> HTML tag inside a quoted (literal) string, the tag is treated as a closing tag rather than as a portion of the string. So you cannot directly use the </script> tag inside a script section. One work-around is to escape the </script> tags and/or split up the <script> tags: var scriptEnd = "<\scr" + "ipt>"; document.write(scriptEnd);

    Multiplication Table

    Create a simple multiplication table asking the user the number of rows and columns he wants. Solution: <html> <head> <title>Multiplication Table</title> <script type="text/javascript"> var rows = prompt("How many rows for your multiplication table?"); var cols = prompt("How many columns for your multiplication table?"); if(rows == "" || rows == null) rows = 10; if(cols== "" || cols== null) cols = 10; createTable(rows, cols); function createTable(rows, cols) { var j=1; var output = "<table border='1' width='500' cellspacing='0'cellpadding='5'>"; for(i=1;i<=rows;i++) { output = output + "<tr>"; while(j<=cols) { output = output + "<td>" + i*j + "</td>"; j = j+1; } output = output + "</tr>"; j = 1; } output = output + "</table>"; document.write(output); } </script> </head> <body> </body> </html>

    JS Forms Example:

    Create a sample form program that collects the first name, last name, email, user id, password and confirms password from the user. All the inputs are mandatory and email address entered should be in correct format. Also, the values entered in the password and confirm password textboxes should be the same. After validating using JavaScript, In output display proper error messages in red color just next to the textbox where there is an error. Solution with Source Code: <html> <head> <title>Form Validation</title> <script type="text/javascript"> var divs = new Array(); divs[0] = "errFirst"; divs[1] = "errLast"; divs[2] = "errEmail"; divs[3] = "errUid"; divs[4] = "errPassword"; divs[5] = "errConfirm"; function validate(){ var inputs = new Array(); inputs[0] = document.getElementById('first').value; inputs[1] = document.getElementById('last').value; inputs[2] = document.getElementById('email').value; inputs[3] = document.getElementById('uid').value; inputs[4] = document.getElementById('password').value; inputs[5] = document.getElementById('confirm').value; var errors = new Array(); errors[0] = "<span style='color:red'>Please enter your first name!</span>"; errors[1] = "<span style='color:red'>Please enter your last name!</span>"; errors[2] = "<span style='color:red'>Please enter your email!</span>"; errors[3] = "<span style='color:red'>Please enter your user id!</span>"; errors[4] = "<span style='color:red'>Please enter your password!</span>"; errors[5] = "<span style='color:red'>Please confirm your password!</span>"; for (i in inputs) { var errMessage = errors[i]; var div = divs[i]; if (inputs[i] == "") document.getElementById(div).innerHTML = errMessage; else if (i==2) { var atpos=inputs[i].indexOf("@"); var dotpos=inputs[i].lastIndexOf("."); if (atpos<1 || dotpos<atpos+2 || dotpos+2>=inputs[i].length) document.getElementById('errEmail').innerHTML = "<span style='color: red'>Enter a valid email address!</span>"; else document.getElementById(div).innerHTML = "OK!"; } else if (i==5) { var first = document.getElementById('password').value; var second = document.getElementById('confirm').value; if (second != first) document.getElementById('errConfirm').innerHTML = "<span style='color: red'>Your passwords don't match!</span>"; else document.getElementById(div).innerHTML = "OK!"; } else document.getElementById(div).innerHTML = "OK!"; } } function finalValidate() { var count = 0; for(i=0;i<6;i++) { var div = divs[i]; if(document.getElementById(div).innerHTML == "OK!") count = count + 1; } if(count == 6) document.getElementById("errFinal").innerHTML = "All the data you entered is correct!!!"; } </script> </head> <body><table id="table1"> <tr> <td>First Name:</td> <td><input type="text" id="first" onkeyup="validate();" /></td> <td><div id="errFirst"></div></td> </tr> <tr> <td>Last Name:</td> <td><input type="text" id="last" onkeyup="validate();"/></td> <td><div id="errLast"></div></td> </tr> <tr> <td>Email:</td> <td><input type="text" id="email" onkeyup="validate();"/></td> <td><div id="errEmail"></div></td> </tr> <tr> <td>User Id:</td> <td><input type="text" id="uid" onkeyup="validate();"/></td> <td><div id="errUid"></div></td> </tr> <tr> <td>Password:</td> <td><input type="password" id="password" onkeyup="validate();"/></td> <td><div id="errPassword"></div></td> </tr> <tr> <td>Confirm Password:</td> <td><input type="password" id="confirm" onkeyup="validate();"/></td> <td><div id="errConfirm"></div></td> </tr> <tr> <td><input type="button" id="create" value="Create" onclick="validate();finalValidate();"/></td> <td><div id="errFinal"></div></td> </tr></table> </body> </html>

    Argument Example

    The arguments object is an array-like object (in that the structure of the object is similar to that of an array; however it should not be considered an array as it has all the functionality of an object) that stores all of the arguments that you passed to a function and is proprietary to that function in particular. If you were to pass 3 arguments to a function, say storeNames(), those 3 arguments would be stored inside an object called arguments and it would look like this when we pass the arguments storeNames("Mulder", "Scully", "Alex Krycek") to our function:
    • First, we declare a function and make it return the arguments object.
    • Then, when we execute that function with n arguments, 3 in this case, it will return the object to us and it will look like an array. We can convert it to an array, but more on that later…
    function storeNames() { return arguments; } // If we execute the following line in the console: storeNames("Mulder", "Scully", "Alex Kryceck"); // The output will be { '0': 'Mulder', '1': 'Scully', '2': 'Alex Kryceck' }

    Treat it as an array

    You can invoke arguments by using arguments[n] (where n is the index of the argument in the array-like object). But if you want to use it as an array for iteration purposes or applying array methods to it, you need to convert it to an array by declaring a variable and using the Array.prototype.slice.call method (because arguments is not an array): var args = Array.prototype.slice.call(arguments); // or the es6 way: var args = Array.from(arguments) Since slice() has two (the parameter end is optional) parameters. You can grab a certain portion of the arguments by specifying the beginning and the ending of your portion (using the slice.call() method renders these two parameters optional, not just end). Check out the following code: function getGrades() { var args = Array.prototype.slice.call(arguments, 1, 3); return args; } // Let's output this! console.log(getGrades(90, 100, 75, 40, 89, 95)); // OUTPUT SHOULD BE: // // [100, 75] <- Why? Because it started from index 1 and stopped at index 3 // so, index 3 (40) wasn't taken into consideration. // // If we remove the '3' parameter, leaving just (arguments, 1) we'd get // every argument from index 1: [100, 75, 40, 89, 95].

    Optimization issues with Array.slice()

    There is a little problem: it’s not recommended to use slice in the arguments object (optimization reasons)… Important: You should not slice on arguments because it prevents optimizations in JavaScript engines (V8 for example). Instead, try constructing a new array by iterating through the arguments object. So, what other method is available to convert arguments to an array? I recommend the for-loop (not the for-in loop). You can do it like this: var args = []; // Empty array, at first. for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]) } // Now 'args' is an array that holds your arguments. For more information on the optimization issues:
    Optimization Killers: Managing Arguments

    ES6 rest parameter as a way to circumvent the arguments object

    In ES2015/ES6 it is possible to use the rest parameter (...) instead of the arguments object in most places. Say we have the following function(non-ES6): function getIntoAnArgument() { var args = arguments.slice(); args.forEach(function(arg) { console.log(arg); }); } That function can be replaced in ES6 by: function getIntoAnArgument(...args) { args.forEach(arg => console.log(arg)); } Note that we also used an arrow function to shorten the forEach callback! The arguments object is not available inside the body of an arrow function. The rest parameter must always come as the last argument in your function definition.
    function getIntoAnArgument(arg1, arg2, arg3, ...restOfArgs /*no more arguments allowed here*/) { //function body }

    Arithmetic Operation Example

    JavaScript provides the user with five arithmetic operators: +, -, *, / and %. The operators are for addition, subtraction, multiplication, division and remainder, respectively. + Addition - Subtraction * Multiplication ** Exponentiation / Division % Modulus (Remainder) ++ Increment -- Decrement

    Addition

    a + b true + 2 // interprets true as 1 and returns 3 false + 5 // interprets false as 0 and returns 5 true + "bar" // concatenates the boolean value and returns "truebar" 5 + "foo" // concatenates the string and the number and returns "5foo" "foo" + "bar" // concatenates the strings and returns "foobar" Hint: There is a handy increment operator that is a great shortcut when you’re adding numbers by 1. Increment & Decrement Increment — x++ or ++x Decrement — x-- or --x Using ++/-- After the Operand When you use the increment/decrement operator after the operand, the value will be returned before the operand is increased/decreased. // Increment let a = 1; console.log(a++); // 1 console.log(a); // 2 // Decrement let b = 1; console.log(b--); // 1 console.log(b); // 0 Using ++/-- Before the Operand If you’d rather make the variable increment/decrement before returning, you simply have to use the increment/decrement operator before the operand: // Increment let a = 1; console.log(++a); // 2 console.log(a); // 2 // Decrement let b = 1; console.log(--b); // 0 console.log(b); // 0

    Subtraction

    a - b false - 5 // interprets false as 0 and returns -5 true + 3 // interprets true as 1 and returns 4 5 + "foo" // returns NaN (Not a Number) Hint: There is a handy decrement operator that is a great shortcut when you’re subtracting numbers by 1.

    Multiplication

    a * b false * 5 // interprets false as 0 and returns 0 true * 3 // interprets true as 1 and returns 3 5 * "foo" // returns NaN (Not a Number) Infinity * 0 // returns NaN Infinity * Infinity // returns Infinity Hint: When making calculations it is possible to use parentheses to prioritize which numbers should be multiplied together.

    Division

    a / b 3 / 0 // returns Infinity 3.0 / 0.0 // returns Infinity -3 / 0 // returns -Infinity false / 5 // interprets false as 0 and returns 0 true / 2 // interprets true a 1 and returns 0.5 Infinity / Infinity // returns NaN

    Remainder

    a % b 3 % 2 // returns 1 true % 5 // interprets true as 1 and returns 1 false % 4 // interprets false as 0 and returns 0 3 % "bar" // returns NaN

    Increment

    a++ or ++a // Postfix x = 3; // declare a variable y = x++; // y = 4, x = 3 // Prefix var a = 2; b = ++a; // a = 3, b = 3

    Decrement

    a-- or --a // Postfix x = 3; // declare a variable y = x—; // y = 3, x = 3 // Prefix var a = 2; b = —a; // a = 1, b = 1 Important: As you can see, you cannot perform any sort of operations on Infinity.

    Arrow Function Example

    Arrow functions are a new ES6 syntax for writing JavaScript function expressions. The shorter syntax saves time, as well as simplifying the function scope.

    What are arrow functions? =>

    An arrow function expression is a more concise syntax for writing function expressions using a “fat arrow” token (=>).

    The basic syntax

    Below is a basic example of an arrow function: // ES5 syntax var multiply = function(x, y) { return x * y;}; // ES6 arrow function var multiply = (x, y) => { return x * y; }; // Or even simpler var multiply = (x, y) => x * y; You no longer need the function and return keywords, or even the curly brackets.

    A simplified this

    Before arrow functions, new functions defined their own this value. To use this inside a traditional function expression, we have to write a workaround like so: // ES5 syntax function Person() { // we assign `this` to `self` so we can use it later var self = this; self.age = 0; setInterval(function growUp() { // `self` refers to the expected object self.age++; }, 1000); } An arrow function doesn’t define its own this value, it inherits this from the enclosing function: // ES6 syntax function Person(){ this.age = 0; setInterval(() => { // `this` now refers to the Person object, brilliant! this.age++; }, 1000); } var p = new Person();

    Assignment Operators

    Assignment Operator Example

    Assignment operators, as the name suggests, assign (or re-assign) values to a variable. While there are quite a few variations on the assignment operators, they all build off of the basic assignment operator. Syntax = y;DescriptionNecessityxVariableRequired=Assignment operatorRequiredyValue to assign to variableRequired Examples let initialVar = 5; // Variable initialization requires the use of an assignment operator let newVar = 5; newVar = 6; // Variable values can be modified using an assignment operator

    Variations

    The other assignment operators are a shorthand for performing some operation using the variable (indicated by x above) and value (indicated by y above) and then assigning the result to the variable itself. For example, below is the syntax for the addition assignment operator: x += y; This is the same as applying the addition operator and reassigning the sum to the original variable (that is, x), which can be expressed by the following code: x = x + y; To illustrate this using actual values, here is another example of using the addition assignment operator: let myVar = 5; // value of myVar: 5 myVar += 7; // value of myVar: 12 = 5 + 7

    Boolean Example

    Booleans are a primitive datatype commonly used in computer programming languages. By definition, a boolean has two possible values: true or false. In JavaScript, there is often implicit type coercion to boolean. If for example you have an if statement which checks a certain expression, that expression will be coerced to a boolean: var a = 'a string'; if (a) { console.log(a); // logs 'a string' } There are only a few values that will be coerced to false:
    • false (not really coerced, as it already is false)
    • null
    • undefined
    • NaN
    • 0
    • ” (empty string)
    All other values will be coerced to true. When a value is coerced to a boolean, we also call that either ‘falsy’ or ‘truthy’. One way that type coercion is used is with the use of the or (||) and and (&&) operators: var a = 'word'; var b = false; var c = true; var d = 0 var e = 1 var f = 2 var g = null console.log(a || b); // 'word' console.log(c || a); // true console.log(b || a); // 'word' console.log(e || f); // 1 console.log(f || e); // 2 console.log(d || g); // null console.log(g || d); // 0 console.log(a && c); // true console.log(c && a); // 'word' As you can see, the or operator checks the first operand. If this is true or truthy, it returns it immediately (which is why we get ‘word’ in the first case & true in the second case). If it is not true or truthy, it returns the second operand (which is why we get ‘word’ in the third case). With the and operator it works in a similar way, but for ‘and’ to be true, both operands need to be truthy. So it will always return the second operand if both are true/truthy, otherwise it will return false. That is why in the fourth case we get true and in the last case we get ‘word’.

    The Boolean Object

    There is also a native JavaScript Boolean object that wraps around a value and converts the first parameter to a boolean value. If a value is omitted or falsy –0, -0, null, false, NaN, undefined, or an empty string ("") – the object's value is false. Pass all other values, including the string "false", and the object's value is set to true. Note that primitive Boolean values (true and false) are different than those of the Boolean object.

    More Details

    Remember that any object, the value of which is not undefined or null, evaluates to true if used in a conditional statement. For example, even though this Boolean object is explicitly set to false, it evaluates to true and the code is executed: var greeting = new Boolean(false); if (greeting) { console.log("Hello world"); } // Hello world This doesn't apply to boolean primitives: var greeting = false; if (greeting) { console.log("Hello world"); // code will not run } To convert a non-boolean value to a boolean, use Boolean as a function rather than as an object: var x = Boolean(expression); // preferred use as a function var x = new Boolean(expression); // don't do it this way

    Callback Functions

    Functions are Objects

    The first thing we need to know is that in JavaScript, functions are first-class objects. As such, we can work with them in the same way we work with other objects, like assigning them to variables and passing them as arguments into other functions. This is important, because it’s the latter technique that allows us to extend functionality in our applications.

    Callback Function Example

    A callback function is a function that is passed as an argument to another function, to be “called back” at a later time. A function that accepts other functions as arguments is called a higher-order function, which contains the logic for when the callback function gets executed. It’s the combination of these two that allow us to extend our functionality. To illustrate callbacks, let’s start with a simple example: function createQuote(quote, callback){ // here callback is variable var myQuote = "Like I always say, " + quote; callback(myQuote); // 2, this call is not fixed, depend on the true calling command } function logQuote(quote){ console.log(quote); } createQuote("eat your vegetables!", logQuote); // 1 // Result in console: // Like I always say, eat your vegetables! In the above example, createQuote is the higher-order function, which accepts two arguments, the second one being the callback. The logQuote function is being used to pass in as our callback function. When we execute the createQuote function <em>(1), notice that we are not appending parentheses to logQuote when we pass it in as an argument. This is because we do not want to execute our callback function right away, we simply want to pass the function definition along to the higher-order function so that it can be executed later. Also, we need to ensure that if the callback function we pass in expects arguments, we supply those arguments when executing the callback (2). In the above example, that would be the callback(myQuote);statement, since we know that logQuote expects a quote to be passed in. Additionally, we can pass in anonymous functions as callbacks. The below call to createQuote would have the same result as the above example: createQuote("eat your vegetables!", function(quote){ console.log(quote); }); Incidentally, you don’t have to use the word “callback” as the name of your argument. JavaScript just needs to know that it’s the correct argument name. Based on the above example, the below function will behave in exactly the same manner. function createQuote(quote, functionToCall) { var myQuote = "Like I always say, " + quote; functionToCall(myQuote); }

    Why use Callbacks?

    Most of the time we are creating programs and applications that operate in a synchronous manner. In other words, some of our operations are started only after the preceding ones have completed. Often when we request data from other sources, such as an external API, we don’t always know when our data will be served back. In these instances we want to wait for the response, but we don’t always want our entire application grinding to a halt while our data is being fetched. These situations are where callback functions come in handy. Let’s take a look at an example that simulates a request to a server: function serverRequest(query, callback){ setTimeout(function(){ var response = query + "full!"; callback(response); },5000); } function getResults(results){ console.log("Response from the server: " + results); } serverRequest("The glass is half ", getResults); // Result in console after 5 second delay: // Response from the server: The glass is half full! In the above example, we make a mock request to a server. After 5 seconds elapse, the response is modified and then our callback function getResults gets executed. To see this in action, you can copy/paste the above code into your browser’s developer tool and execute it. Also, if you are already familiar with setTimeout, then you’ve been using callback functions all along. The anonymous function argument passed into the above example’s setTimeout function call is also a callback! So the example’s original callback is actually executed by another callback. Be careful not to nest too many callbacks if you can help it, as this can lead to something called “callback hell”! As the name implies, it isn’t a joy to deal with. function print(callback) { callback(); } The print( ) function takes another function as a parameter and calls it inside. This is valid in JavaScript and we call it a “callback”. So a function that is passed to another function as a parameter is a callback function. But that’s not all. Callbacks make sure that a function is not going to run before a task is completed but will run right after the task has completed. It helps us develop asynchronous JavaScript code and keeps us safe from problems and errors. In JavaScript, the way to create a callback function is to pass it as a parameter to another function, and then to call it back right after something has happened or some task is completed.

    How to create a Callback

    example We want to log a message to the console but it should be there after 3 seconds. const message = function() { console.log("This message is shown after 3 seconds"); } setTimeout(message, 3000); There is a built-in method in JavaScript called “setTimeout”, which calls a function or evaluates an expression after a given period of time (in milliseconds). So here, the “message” function is being called after 3 seconds have passed. (1 second = 1000 milliseconds) In other words, the message function is being called after something happened (after 3 seconds passed for this example), but not before. So the message function is an example of a callback function.

    What is an Anonymous Function?

    Alternatively, we can define a function directly inside another function, instead of calling it. It will look like this: setTimeout(function() { console.log("This message is shown after 3 seconds"); }, 3000); As we can see, the callback function here has no name and a function definition without a name in JavaScript is called as an “anonymous function”. This does exactly the same task as the example above.

    Callback as an Arrow Function

    If you prefer, you can also write the same callback function as an ES6 arrow function, which is a newer type of function in JavaScript: setTimeout(() => { console.log("This message is shown after 3 seconds"); }, 3000);

    Class Example

    JavaScript Class JavaScript does not have the concept of classes inherently. But we could simulate the functionalities of a class by taking advantage of the prototypal nature of JavaScript. This section assumes that you have a basic understanding of prototypes. For the sake of clarity, let us assume that we want to create a class which can do the following var p = new Person('James','Bond'); // create a new instance of Person classp.log() // Output: 'I am James Bond' // Accessing a function in the class// Using setters and getters p.profession = 'spy'p.profession // output: James bond is a spy

    Using class keyword

    Like in any other programming language, you can now use the class keyword to create a class. This is not supported in older browsers and was introduced in ECMAScript 2015. class is just a syntactic sugar over JavaScript’s existing prototype-based inheritance model. In general, programmers use the following ways to create a class in JavaScript.

    Using methods added to prototypes:

    Here, all the methods are added to prototype function Person(firstName, lastName) { this._firstName = firstName; this._lastName = lastName; } Person.prototype.log = function() { console.log('I am', this._firstName, this._lastName); } // This line adds getters and setters for the profession object. Note that in general you could just write your own get and set functions like the 'log' method above. // Since in this example we are trying the mimic the class above, we try to use the getters and setters property provided by JavaScript Object.defineProperty(Person.prototype, 'profession', { set: function(val) { this._profession = val; }, get: function() { console.log(this._firstName, this._lastName, 'is a', this._profession); } }) You could also write prototype methods over function Person as below: Person.prototype = { log: function() { console.log('I am ', this._firstName, this._lastName); } set profession(val) { this._profession = val; } get profession() { console.log(this._firstName, this._lastName, 'is a', this._profession); } }

    Using methods added internally

    Here the methods are added internally instead of prototype: function Person(firstName, lastName) { this._firstName = firstName; this._lastName = lastName; this.log = function() { console.log('I am ', this._firstName, this._lastName); } Object.defineProperty(this, 'profession', { set: function(val) { this._profession = val; }, get: function() { console.log(this._firstName, this._lastName, 'is a', this._profession); } }) }

    Hiding details in classes with symbols

    Most often, some properties and methods have to be hidden to prevent access from outside the function. With classes, to obtain this functionality, one way to do this is by using symbols. Symbol is a new built-in type of JavaScript, which can be invoked to give a new symbol value. Every Symbol is unique and can be used as a key on object. So one use case of symbols is that you can add something to an object you might not own, and you might not want to collide with any other keys of object. Therefore, creating a new one and adding it as a property to that object using symbol is the safest. Also, when symbol value is added to an object, no one else will know how to get it. class Person { constructor(firstName, lastName) { this._firstName = firstName; this._lastName = lastName; } log() { console.log('I am', this._firstName, this._lastName); } // setters set profession(val) { this._profession = val; } // getters get profession() { console.log(this._firstName, this._lastName, 'is a', this._profession); } // With the above code, even though we can access the properties outside the function to change their content what if we don't want that. // Symbols come to rescue. let s_firstname = new Symbol(); class Person { constructor(firstName, lastName) { this[s_firstName] = firstName; this._lastName = lastName; } log() { console.log('I am', this._firstName, this._lastName); } // setters set profession(val) { this._profession = val; } // getters get profession() { console.log(this[s_firstName], this._lastName, 'is a', this._profession); }

    JavaScript Closure Example

    A closure is the combination of a function and the lexical environment (scope) within which that function was declared. Closures are a fundamental and powerful property of Javascript. This section discusses the ‘how’ and ‘why’ about Closures:

    Example

    //we have an outer function named walk and an inner function named fly function walk (){ var dist = '1780 feet'; function fly(){ console.log('At '+dist); } return fly; } var flyFunc = walk(); //calling walk returns the fly function which is being assigned to flyFunc //you would expect that once the walk function above is run //you would think that JavaScript has gotten rid of the 'dist' var flyFunc(); //Logs out 'At 1780 feet' //but you still can use the function as above //this is the power of closures

    Another Example

    function by(propName) { return function(a, b) { return a[propName] - b[propName]; } } const person1 = {name: 'joe', height: 72}; const person2 = {name: 'rob', height: 70}; const person3 = {name: 'nicholas', height: 66}; const arr_ = [person1, person2, person3]; const arr_sorted = arr_.sort(by('height')); // [ { name: 'nicholas', height: 66 }, { name: 'rob', height: 70 },{ name: 'joe', height: 72 } ] The closure ‘remembers’ the environment in which it was created. This environment consists of any local variables that were in-scope at the time the closure was created. function outside(num) { var rememberedVar = num; // In this example, rememberedVar is the lexical environment that the closure 'remembers' return function inside() { // This is the function which the closure 'remembers' console.log(rememberedVar) } } var remember1 = outside(7); // remember1 is now a closure which contains rememberedVar = 7 in its lexical environment, and //the function 'inside' var remember2 = outside(9); // remember2 is now a closure which contains rememberedVar = 9 in its lexical environment, and //the function 'inside' remember1(); // This now executes the function 'inside' which console.logs(rememberedVar) => 7 remember2(); // This now executes the function 'inside' which console.logs(rememberedVar) => 9 Closures are useful because they let you ‘remember’ data and then let you operate on that data through returned functions. This allows Javascript to emulate private methods that are found in other programming languages. Private methods are useful for restricting access to code as well as managing your global namespace.

    Private variables and methods

    Closures can also be used to encapsulate private data/methods. Take a look at this example: const bankAccount = (initialBalance) => { const balance = initialBalance; return { getBalance: function() { return balance; }, deposit: function(amount) { balance += amount; return balance; }, }; }; const account = bankAccount(100); account.getBalance(); // 100 account.deposit(10); // 110 In this example, we won’t be able to access balance from anywhere outside of the bankAccount function, which means we’ve just created a private variable. Where’s the closure? Well, think about what bankAccount() is returning. It actually returns an Object with a bunch of functions inside it, and yet when we call account.getBalance(), the function is able to “remember” its initial reference to balance. That is the power of the closure, where a function “remembers” its lexical scope (compile time scope), even when the function is executed outside that lexical scope.

    Emulating block-scoped variables

    Javascript did not have a concept of block-scoped variables. Meaning that when defining a variable inside a for-loop, for example, this variable was visible from outside the for-loop as well. So how can closures help us solve this problem? Let’s take a look. var funcs = []; for(var i = 0; i < 3; i++){ funcs[i] = function(){ console.log('My value is ' + i); //creating three different functions with different param values. } } for(var j = 0; j < 3; j++){ funcs[j](); // My value is 3 // My value is 3 // My value is 3 } Since the variable i does not have block-scope, it’s value within all three functions was updated with the loop counter and created malicious values. Closures can help us solve this issue by creating a snapshot of the environment the function was in when it was created, preserving its state. var funcs = []; var createFunction = function(val){ return function() {console.log("My value: " + val);}; } for (var i = 0; i < 3; i++) { funcs[i] = createFunction(i); } for (var j = 0; j < 3; j++) { funcs[j](); // My value is 0 // My value is 1 // My value is 2 } The later versions of Javascript (ES6+) have a new keyword called let which can be used to give the variable a blockscope. There are also many functions (forEach) and entire libraries (lodash.js) that are dedicated to solving such problems as the ones explained above. They can certainly boost your productivity, however it remains extremely important to have knowledge of all these issues when attempting to create something big. Closures have many special applications that are useful when creating large Javascript programs.
    1. Emulating private variables or encapsulation
    2. Making Asynchronous server side calls
    3. Creating a block-scoped variable.

    Emulating private variables

    Unlike many other languages, Javascript does not have a mechanism which allows you to create encapsulated instance variables within an object. Having public instance variables can cause a lot of problems when building medium to large programs. However with closures, this problem can be mitigated. Much like in the previous example, you can build functions which return object literals with methods that have access to the object’s local variables without exposing them. Thus, making them effectively private. Closures can also help you manage your global namespace to avoid collisions with globally shared data. Usually, all global variables are shared between all scripts in your project, which will definitely give you a lot of trouble when building medium to large programs. That is why library and module authors use closures to hide an entire module’s methods and data. This is called the module pattern, it uses an immediately invoked function expression which exports only certain functionality to the outside world, significantly reducing the amount of global references. Here’s a short sample of a module skeleton. var myModule = (function() = { let privateVariable = 'I am a private variable'; let method1 = function(){ console.log('I am method 1'); }; let method2 = function(){ console.log('I am method 2, ', privateVariable); }; return { method1: method1, method2: method2 } }()); myModule.method1(); // I am method 1 myModule.method2(); // I am method 2, I am a private variable Closures are useful for capturing new instances of private variables contained in the ‘remembered’ environment, and those variables can only be accessed through the returned function or methods.

    JavaScript Comment Example

    Programmers use comments to add hints, notes, suggestions, or warnings to their source code; they have no effect on the actual output of the code. Comments can be very helpful in explaining the intent of what your code is or should be doing. It is always best practice when starting out to comment more often than not, as it can help those reading your code to understand what exactly your code is intending to do. JavaScript has two ways of assigning comments in its code. The first way is the // comment; all text following // on the same line into a comment. For example: function hello() { // This is a one line JavaScript comment console.log("Hello world!"); } hello(); The second way is the /* */ comment, which can be used for both single-line and multi-line comments. For example: function hello() { /* This is a one line JavaScript comment */ console.log("Hello world!"); } hello(); function hello() { /* This comment spans multiple lines. Notice that we don't need to end the comment until we're done. */ console.log("Hello world!"); } hello(); You can also prevent execution of Javascript code just commeting the code lines like this: function hello() { /*console.log("Hello world!");*/ } hello();

    More Information:

    How To Write Comments in JavaScript

    Many IDEs come with a keyboard shortcut to comment out lines.

    1. Highlight text to be commented
    2. Mac: Push Command(Apple Key) & "/"
    3. Windows: Push Control & "/"
    4. You can also uncomment code by doing the same steps
    A shortcut to comment out a section of Javascript in many code editors is to highlight the lines of code you want to comment out, then press `Cmd/Ctrl + /`. Comments are also very helpful for code testing as you can prevent a certain code-line/block from running: function hello() { // The statement below is not going to get executed // console.log('hi') } hello(); function hello() { // The statements below are not going to get executed /* console.log('hi'); console.log('code-test'); */ } hello();

    Comparison Operator Example

    JavaScript has both strict and type–converting comparisons.
    • The strict comparison (===) only evaluates to true if both operands are the same type.
    • The abstract comparison (==) attempts to convert both operands to the same type before comparing them.
    • With relational abstract comparisons (<=), both operands are converted to primitives, then to the same type before comparison.
    • Strings are compared using Unicode values based on standard ordering.

    Features of comparisons:

    • Two strings are considered strictly equal when they have the characters in the same sequence and the same length.
    • Two numbers are considered strictly equal when they are the both of the type number and are numerically equal. This means that both 0 and -0 are strictly equal since they both evaluate to 0. Note that NaN is a special value and is not equal to anything, including NaN.
    • Two Boolean operands are considered strictly equal if both are true or false.
    • Two objects are never considered equal in both strict or abstract comparisons.
    • Expressions that compare objects are only considered true if the operands both reference the same exact object instance.
    • Null and undefined are both considered strictly equal to themselves (null === null) and abstractly equal to each other (null == undefined)

    Equality operators

    Equality (==)

    The equality operator first converts operands that are not of the same type, then strictly compares them to one another.

    Syntax

    x == y

    Examples

    1 == 1 // true "1" == 1 // true 1 == '1' // true 0 == false // true 0 == null // false 0 == undefined // false null == undefined // true

    Inequality (!=)

    The inequality operator evaluates to true if both operands are not equal. If the operands are not the same type, it will try to convert them to the same type before making the comparison.

    Syntax

    x != y

    Examples

    1 != 2 // true 1 != "1" // false 1 != '1' // false 1 != true // false 0 != false // false

    Identity / strict equality (===)

    The identity or strict equality operator returns true if both operands are strictly equal in terms of value and type. Unlike the equality operator (==), it will not attempt to convert the operands to the same type.

    Syntax

    x === y

    Examples

    3 === 3 // true 3 === '3' // false

    Non-identity / strict inequality (!==)

    The non-identity or strict inequality operator returns true if both operands are not strictly equal in terms of value or type.

    Syntax

    x !== y

    Examples

    3 !== '3' // true 4 !== 3 // true

    Relational operators

    Greater than operator (>)

    The greater than operator returns true if the operand on the left is greater than the one on the right.

    Syntax

    x > y

    Examples

    4 > 3 // true

    Greater than or equal operator (>=)

    The greater than or equal operator returns true if the operand on the left is greater than or equal to the one on the right.

    Syntax

    x >= y

    Examples

    4 >= 3 // true 3 >= 3 // true

    Less than operator (<)

    The less than operator returns true if the operand on the left is less than the one on the right.

    Syntax

    x < y

    Examples

    3 < 4 // true

    Less than or equal operator (<=)

    The less than or equal operator returns true if the operand on the left is less than or equal to the one on the right.

    Syntax

    x <= y

    Examples

    3 <= 4 // true

    Form Validation Example

    Form validation used to occur at the server, after the client had entered all the necessary data and then pressed the Submit button. If the data entered by a client was incorrect or was simply missing, the server would have to send all the data back to the client and request that the form be resubmitted with correct information. This was really a lengthy process which used to put a lot of burden on the server. JavaScript provides a way to validate form’s data on the client’s computer before sending it to the web server. Form validation generally performs two functions:

    Basic Validation

    First of all, the form must be checked to make sure all the mandatory fields are filled in. It just requires a loop through each field in the form to check for data.

    Data Format Validation

    Secondly, the data that is entered must be checked for correct form and value. Your code must include appropriate logic to test the correctness of the data.

    Example:

    <html> <head> <title>Form Validation</title> <script type="text/javascript"> <!-- // Form validation code will come here. //--> </script> </head> <body> <form action="/cgi-bin/test.cgi" name="myForm" onsubmit="return(validate());"> <table cellspacing="2" cellpadding="2" border="1"> <tr> <td align="right">Name</td> <td><input type="text" name="Name" /></td> </tr> <tr> <td align="right">EMail</td> <td><input type="text" name="EMail" /></td> </tr> <tr> <td align="right">Zip Code</td> <td><input type="text" name="Zip" /></td> </tr> <tr> <td align="right">Country</td> <td> <select name="Country"> <option value="-1" selected>[choose yours]</option> <option value="1">USA</option> <option value="2">UK</option> <option value="3">INDIA</option> </select> </td> </tr> <tr> <td align="right"></td> <td><input type="submit" value="Submit" /></td> </tr> </table> </form> </body> </html>

    Output

    Have a look here.

    Basic Form Validation

    First let us see how to do a basic form validation. In the above form, we are calling validate() to validate data when the onsubmit event is occurring. The following code shows the implementation of this validate()function. <script type="text/javascript"> // Form validation code will come here. function validate() { if( document.myForm.Name.value == "" ) { alert( "Please provide your name!" ); document.myForm.Name.focus() ; return false; } if( document.myForm.EMail.value == "" ) { alert( "Please provide your Email!" ); document.myForm.EMail.focus() ; return false; } if( document.myForm.Zip.value == "" || isNaN( document.myForm.Zip.value ) || document.myForm.Zip.value.length != 5 ) { alert( "Please provide a zip in the format #####." ); document.myForm.Zip.focus() ; return false; } if( document.myForm.Country.value == "-1" ) { alert( "Please provide your country!" ); return false; } return( true ); } </script>

    Output

    Have a look here.

    Data Format Validation

    Now we will see how we can validate our entered form data before submitting it to the web server. The following example shows how to validate an entered email address. An email address must contain at least an ‘@’ sign and a dot (.). Also, the ‘@’ must not be the first character of the email address, and the last dot must at least be one character after the ‘@’ sign.

    Example:

    <script type="text/javascript"> function validateEmail() { var emailID = document.myForm.EMail.value; atpos = emailID.indexOf("@"); dotpos = emailID.lastIndexOf("."); if (atpos < 1 || ( dotpos - atpos < 2 )) { alert("Please enter correct email ID") document.myForm.EMail.focus() ; return false; } return( true ); } </script>

    Output

    Have a look here.

    HTML5 Form Constraints

    Some of the commonly used HTML5 constraints for <input> are the type attribute (e.g. type="password"), maxlength, required and disabled. A less commonly used constraint is the pattern attribute that takes a JavaScript regular expression.

    If statement example

    The if statement executes a statement if a specified condition is true. If the condition is false, another statement can be executed using the else statement. Note: The else statement is optional. if (condition) /* do something */ else /* do something else */ Multiple if...else statements can be chained to create an else if clause. This specifies a new condition to test and can be repeated to test multiple conditions, checking until a true statement is presented to execute. if (condition1) /* do something */ else if (condition2) /* do something else */ else if (condition3) /* do something else */ else /* final statement */ Note: If you want to execute more than one statement in the if, else or else if part, curly braces are required around the statements: if (condition) { /* do */ /* something */ /* with multiple statements */ } else { /* do something */ /* else */ } MDN link | MSDN link Examples Using if...else: // If x=5 z=7 and q=42. If x is not 5 then z=19. if (x == 5) { z = 7; q = 42 else z = 19; Using else if: if (x < 10) return "Small number"; else if (x < 50) return "Medium number"; else if (x < 100) return "Large number"; else { flag = 1; return "Invalid number"; }

    Prototype Example

    JavaScript is a prototype-based language, therefore understanding the prototype object is one of the most important concepts which JavaScript practitioners need to know. This section will give you a short overview of the Prototype object through various examples. Before reading this part, you will need to have a basic understanding of the this reference in JavaScript.

    Prototype object

    For the sake of clarity, let’s examine the following example: function Point2D(x, y) { this.x = x; this.y = y; } As Point2D function is declared, a default property named prototype will be created for it (note that, in JavaScript, a function is also an object). The prototype property is an object which contains a constructorproperty and its value is Point2D function: Point2D.prototype.constructor = Point2D. And when you call Point2D with new keyword, newly created objects will inherit all properties from Point2D.prototype. To check that, you can add a method named move into Point2D.prototype as follows: Point2D.prototype.move = function(dx, dy) { this.x += dx; this.y += dy; } var p1 = new Point2D(1, 2); p1.move(3, 4); console.log(p1.x); // 4 console.log(p1.y); // 6 The Point2D.prototype is called prototype object or prototype of p1 object and for any other object created with new Point2D(...) syntax. You can add more properties to Point2D.prototype object as you like. The common pattern is to declare methods to Point2D.prototype and other properties will be declared in the constructor function. Built-in objects in JavaScript are constructed in a similar manner. For example:
    • Prototype of objects created with new Object() or {} syntax is Object.prototype.
    • Prototype of arrays created with new Array() or [] syntax is Array.prototype.
    • And so on with other built-in objects such as Date and RegExp.
    Object.prototype is inherited by all objects and it has no prototype (its prototype is null).

    Prototype chain

    The prototype chain mechanism is simple: When you access a property p on object obj, the JavaScript engine will search this property inside obj object. If the engine fails to search, it continues searching in the prototype of obj object and so on until reaching Object.prototype. If after the search has finished, and nothing has been found, the result will be undefined. For example: var obj1 = { a: 1, b: 2 }; var obj2 = Object.create(obj1); obj2.a = 2; console.log(obj2.a); // 2 console.log(obj2.b); // 2 console.log(obj2.c); // undefined In above snippet, the statement var obj2 = Object.create(obj1) will create obj2 object with prototype obj1 object. In other words, obj1 becomes the prototype of obj2 instead of Object.prototype by default. As you can see, b is not a property of obj2; you can still access it via the prototype chain. For the c property, however, you get an undefined value because it can’t be found in obj1 and Object.prototype.

    Classes

    In ES2016, we now get to use the Class keyword as well as the methods mentioned above to manipulate prototype. The JavaScript Class appeals to developers from OOP backgrounds, but it’s essentially doing the same thing as above. class Rectangle { constructor(height, width) { this.height = height this.width = width } get area() { return this.calcArea() } calcArea() { return this.height * this.width } } const square = new Rectangle(10, 10) console.log(square.area) // 100 This is basically the same as: function Rectangle(height, width) { this.height = height this.width = width } Rectangle.prototype.calcArea = function calcArea() { return this.height * this.width } The getter and setter methods in classes bind an Object property to a function that will be called when that property is looked up. It’s just syntactic sugar to help make it easier to look up or set properties.

    Scope Example

    If you’ve been programming in JavaScript for a while, you’ve undoubtedly run into a concept known as scope. What is scope? Why should you take the time to learn it? In programmer speak, scope is the current context of execution. Confused? Let’s take a look at the following piece of code: var foo = 'Hi, I am foo!'; var baz = function() { var bar = 'Hi, I am bar too!'; console.log(foo); } baz(); // Hi, I am foo! console.log(bar); // ReferenceError... This is a simple example, but it does a good job of illustrating what is known as Lexical scope. JavaScript, and almost every other programming language, has a Lexical scope. There is another kind of scope known as Dynamic scope, but we won’t be discussing that. Now, the term Lexical scope sounds fancy, but as you will see it’s really simple in principle. In a Lexical Scope, there are two kinds of scopes: the global scope and a local scope. Before you type the first line of code in your program, a global scope is created for you. This contains all the variables that you declare in your program outside any functions. In the example above, the variable foo is in the global scope of the program, while the variable bar is declared inside a function and is therefore in the local scope of that function. Let's break down the example line by line. While you might be confused at this point, I promise you will have a much better understanding by the time you finish reading this. On line 1 we are declaring the variable foo. Nothing too fancy here. Let's call this a left-hand size (LHS) reference to foo, because we are assigning a value to foo and it’s on the left-hand side of the equal sign. On line 3, we are declaring a function and assigning it to variable baz. This is another LHS reference to baz. We are assigning a value to it (remember, functions are values too!). This function is then called on line 8. This is a RHS, or a right-hand side reference to baz. We are retrieving baz’s value, which in this case is a function and then invoking it. Another RHS reference to baz would be if we assigned its value to another variable, for example foo = baz. This would be a LHS reference to foo and a RHS reference to baz. The LHS and RHS references might sound confusing, but they are important for discussing scope. Think of it this way: a LHS reference is assigning a value to the variable, while a RHS reference is retrieving the value of the variable. They’re just a shorter and more convenient way of saying ‘retrieving the value’ and ‘assigning a value’. Let’s now break down what’s happening inside the function itself. When the compiler compiles the code inside a function, it enters the function’s local scope. On line 4, the variable bar is declared. This is a LHS reference to bar. On the next line, we have a RHS reference to foo inside the console.log(). Remember, we are retrieving foo’s value and then passing it as an argument to the method console.log(). When we have a RHS reference to foo, the compiler looks for the declaration of the variable foo. The compiler doesn’t find it in the function itself, or the function’s local scope, so it goes up one level: to the global scope. At this point you’re probably thinking that scope has something to do with variables. That is correct. A scope can be thought of as a container for variables. All variables that are created within a local scope are only accessible in that local scope. However, all local scopes can access the global scope. (I know you’re probably even more confused right now, but just bear with me for a few more paragraphs). So the compiler goes up to the global scope to find a LHS reference to the variable foo. It finds one on line 1, so it retrieves the value from the LHS reference, which is a string: 'Hi, I am foo!'. This string is sent to the console.log() method, and outputted to the console. The compiler has finished executing the code inside the function, so we come back out to line 9. On line 9, we have a RHS reference for the variable bar. Now, bar was declared in the local scope of baz, but there is a RHS reference for bar in the global scope. Since there is no LHS reference for bar in the global scope, the compiler can’t find a value for bar and throws a ReferenceError. But, you might ask, if the function can look outside itself for variables, or a local scope can peek into the global scope to find LHS references, why can’t the global scope peek into a local scope? Well that’s how lexical scope works! ... // global scope var baz = function() { ... // baz's scope } ... /// global scope This is the same code from above which illustrates the scope. This forms a sort of hierarchy that goes up to the global scope: baz -> global. So, if there is a RHS reference for a variable inside baz’s scope, it can be fulfilled by a LHS reference for that variable in the global scope. But the opposite is not true. What if we had another function inside baz? ... // global scope var baz = function() { ... // baz's scope var bar = function() { ... // bar's scope. } } ... /// global scope In this case, the hierarchy or the scope chain would look like this: bar -> baz -> global Any RHS references inside bar’s local scope can be fulfilled by LHS references in the global scope or baz’s scope, but a RHS reference in baz’s scope cannot be fulfilled by a LHS reference in bar’s scope. You can only traverse down a scope chain, not up. There are other two important things you should know about JavaScript scopes.
    1. Scopes are declared by functions, not by blocks.
    2. Functions can be forward-referenced, variables can’t.
    Observe (each comment describes scope at the line that it’s written on): // outer() is in scope here because functions can be forward-referenced function outer() { // only inner() is in scope here // because only functions are forward-referenced var a = 1; //now 'a' and inner() are in scope function inner() { var b = 2 if (a == 1) { var c = 3; } // 'c' is still in scope because JavaScript doesn't care // about the end of the 'if' block, only function inner() } // now b and c are out of scope // a and inner() are still in scope } // here, only outer() is in scope

    Do While loop example

    The do...while loop is closely related to the loop. In the do while loop, the condition is checked at the end of the loop. Here is the syntax for do...while loop: Syntax: do { *Statement(s);* } while (*condition*); statement(s): A statement that is executed at least once before the condition or Boolean expression is evaluated and is re-executed each time the condition evaluates to true. condition: Here, a condition is a Boolean expression. If the Boolean expression evaluates to true, the statement is executed again. When the Boolean expression evaluates to false, the loops ends. Example: var i = 0; do { i = i + 1; console.log(i); } while (i < 5);

    create Desktop Apps

    convert html, css and javascript into a exe Two very good open-source and extremely actively developed options are Electron, by GitHub. Cordova, by the Apache Foundation. Targets Android, iOS, and Windows from HTML/JavaScript/CSS. Proton Native. Works with React Native components and does not use Electron (see above), which makes generated apps therefore more "lightweight" than the ones generated by Electron. HTML Compiler convert an entire HTML application (using CSS, JavaScript, Images and more) into an standalone Windows application. ExeOutput for PHP that lets you create applications in native format for Windows with PHP, JavaScript and HTML. Convert PHP scripts, websites, JavaScript, HTML, databases into stand-alone apps for Windows (single EXE files) that do not require a Web server nor PHP distribution. Electron Electron Electron is an open-source framework initially built by GitHub for Atom editor in 2013. This library lets you create desktop GUI applications with web technologies like JavaScript, HTML and CSS. NW.js NW.js The next on our list of the best JavaScript frameworks for desktop apps is NW.js, previously known as the node-webkit. It was built at Intel’s Open Source Technology Center by combining Node.js framework with a Chromium engine (previously known as Webkit). Available on Linux, Mac OS, and Windows. AppJS AppJS AppJS is a simple yet powerful tool that you can use to build cross-platform apps without the need to learn new languages. Similarly to the other libraries mentioned today, you’re fine as long as you’re familiar with HTML, CSS and JavaScript. Although it’s the oldest Node.js-Chromium framework in the AppJS, Electron and NW.js trio, it’s not nearly as mature as its competition. Because it has lost its momentum, it may not be the best choice for new projects. Meteor Meteor Although it does not build desktop apps on its own, it can be used with Cordova or other similar tools to produce them. It uses MongoDB, Distributed Data Protocol, and a publish-subscribe pattern to auto-propagate the changes without developer interference. It has both front-end and back-end modules, including the API, build tools, Node.js packages. Proton Native Proton Native Proton Native is a fresh release. It was made available on GitHub in the early months of 2018. It works quite differently to Electron, which runs a full Chromium browser to manage a small GUI. Proton Native, on the other hand, uses native tools, takes less space and needs fewer resources. This solution has a few other advantages – it uses the same syntax as React Native, works with React libraries including Redux and is compatible with Node.js. Summary To sum up, JavaScript frameworks for desktop apps can be divided into three categories: Frameworks that produce web browser hosted desktop apps, based on Node.js and Chromium (Electron, NW.js, AppJS). Frameworks that need to be used with Cordova-like tools (Meteor). Frameworks that use genuinely native components to build a desktop app (Proton Native).

    build desktop app with Electron

    build Desktop Apps with HTML, CSS and Javascript

    INSTALL ELECTRON GLOBALLY

    Electron Tutorial - Introduction Install Electron globally on our system using NPM. npm i electron -g

    CREATE AN ELECTRON PROJECT

    1. INITIALIZE THE PROJECT

    First, create a project directory and a package.json file under it. Now direct to the folder and make a package.json inside it. mkdir AwesomeProject cd /AwesomeProject npm init Enter the project details if you wish or skip.

    2. CREATE A VIEW

    Now create the file we wanted to be viewed when opening our app. Electron uses HTML to render the view and so we need to create an index.html file. index.html <html> <head> <title>Hello World Application</title> </head> <body> <h1>Hello World</h1> </body> </html>

    3. CREATE AN INDEX.JS FILE

    In package.json, we programmed that the root file of our project is index.js. So we need to create it. index.js const { app, BrowserWindow } = require("electron"); const url = require("url"); function newApp() { win = new BrowserWindow(); win.loadURL( url.format({ pathname: "index.html", slashes: true }) ); } app.on("ready", newApp);

    4. RUNNING OUR APPLICATION

    Now we can run our Electron app using the command below. electron . Electron Packager 'electron-packager' is not recognized as an internal or external command Install it using: npm install -g electron-packager Suggested to use one of the options from ia32, x64, armv7l, arm64, mips64el electron-packager sourcedir appname --platform=win32 --arch=x64 electron-packager AwesomeProject jsNotes --platform=win32 --arch=x64 electron-packager' is not recognized as an internal or external command, Unable to determine Electron version. Please specify an Electron version my package.json is like this were to put the --electron-version ?? Install electron as dev-dependency to resolve this issue npm install --save-dev electron And to build for Windows you can run this from the git bash: electron-packager . jsNOtes --overwrite --asar=true --platform=win32 --arch=x64 --icon=assets/icons/win/icon.ico --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName="jsNOtes" cannot run app after electron-packager

    A complete guide to packaging your Electron app

    Packaging an electron app simply means creating a desktop installer (dmg, exe, deb etc). Now if you decide to go around manually packaging your app, you’re gonna have a bad time. Luckily there are modules, especially the two mentioned below which make the task easier.
    electron-builder electron-packager
    We’ll be using electron-builder since it has a built-in support for Code Signing/Auto Update etc.

    Configure your app to use electron-builder :

    Create a directory build in the root of the project and save a background.png (macOS DMG background), icon.icns (macOS app icon) and icon.ico (Windows app icon) into it. The Linux icon set will be generated automatically based on the macOS. Ex. zulip-electron/build Add electron-builder to your app devDependencies by running: npm install electron-builder --save-dev In electron-builder you could use two package.json structure as well as single package.json. We’ll be using single package.json structure since it’s easier to maintain.

    Sample One package.json

    { "name": "yourappname", "version": "0.0.1", "license": "MIT", "description": "your app description", "author": "xyz <xyz@gmail.com>", "main": "./app/index.js", "scripts": { "postinstall": "install-app-deps", "start": "npm install && electron ./app", "pack": "build --dir", "dist": "build" }, "build": { "appId": "yourappid", "category": "your.app.category.type", "dmg": { "contents": [ { "x": 110, "y": 150 }, { "x": 240, "y": 150, "type": "link", "path": "/Applications" } ] }, "linux": { "target": [ "AppImage", "deb" ] }, "win": { "target": "squirrel", "icon": "build/icon.ico" } }, "dependencies": {}, "devDependencies": { "electron": "latest", "electron-builder": "latest" } } view rawpackage.json hosted with ❤ by GitHub On windows build you can also use NSIS target which is the default one and recommended by electron-builder. "win": { "target": "NSIS"} That’s it. You’ve successfully configured electron-builder. Now let’s build the installers. To package your app into an installer use command: npm run dist It will create an installer in ./dist folder. By default build command will only generate the installer for current platform and current arch. For an ex. running it on OSX will create — $ npm run dist |-- mac | |-- appname-version-mac.zip | |-- appname-version.dmg | |-- appname.app On Windows - # When using target — Squirrel$ npm run dist |-- win | |-- REALESES | |-- appnameSetupversion.exe | |-- appname-version-full.nupkg |-- win-unpacked# When using target — NSIS$ npm run dist |-- win | |-- appnameSetupversion.exe |-- win-unpacked On Linux - $ npm run dist |-- appname-version.AppImage |-- appname-version.deb |-- linux-unpacked electron-builder is highly configurable. For complete usage check out its wiki. zulip-electron (two package.json) and onshape-desktop-shell (one package.json) are some real world projects that use electron-builder for their packaging.

    scroll to div bottom, scrollTop, clientHeight and offsetTop

    if(testkey == "l"){divtoc = document.getElementById("toc");$('body,html').animate({scrollTop:(divtoc.clientHeight + divtoc.offsetTop-600)}, 1); } if(testkey == 'e'){window.scrollTo(0,document.body.scrollHeight);} if(testkey == 't'){window.location = '#toc';} if(testkey == "k"){ if(typeof bookid == 'undefined') { bookid = $('title').text() } storeBookmark(bookid, topicpointer.toString()); } if(testkey == "K"){ if(typeof bookid != 'undefined') {loadBookmark(bookid);} else{alert("No BookId!")} function storeBookmark(objName, chapterNum) { if(typeof objName != 'undefined') { localStorage.setItem(objName, chapterNum.toString()) }else{alert("No BookId!")} } function loadBookmark(objName) { topicpointer = parseInt(localStorage.getItem(objName)) showImg(); } ================== if(testkey == "k"){ pos = document.getElementsByTagName("body")[0].scrollTop; if(typeof bookid == 'undefined') { bookid = $('title').text() } storeBookmark(bookid, pos.toString()); } if(testkey == "K"){ if(typeof bookid != 'undefined') {loadBookmark(bookid);} else{alert("No BookId!")} } function storeBookmark(objName, pagepos) { if(typeof objName != 'undefined') { localStorage.setItem(objName, pagepos.toString()) // alert("Bookmark changed! " + objName +" " + pagepos) }else{alert("No BookId!")} } function loadBookmark(objName) { pos = Number(localStorage.getItem(objName)) console.log("Bookmark loaded! " + objName + " " + pos) $('body').animate({scrollTop: pos}, 0); }

    lazyload

    lazyload 1 <script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload@13.0.1/dist/lazyload.min.js"></script> 2 <img class="lazy" data-src="lazy.jpg" /> Then, in your javascript code: 3 place script at end of page: var lazyLoadInstance = new LazyLoad({ elements_selector: ".lazy" // ... more custom settings? }); Lazy video <video class="lazy" controls data-src="lazy.mp4" data-poster="lazy.jpg"> <source type="video/mp4" data-src="lazy.mp4" /> <source type="video/ogg" data-src="lazy.ogg" /> <source type="video/avi" data-src="lazy.avi" /> </video> Please note that the video poster can be lazily loaded too. To be sure that DOM for your lazy content is ready when you instantiate LazyLoad, place the script tag right before the closing tag. If more DOM arrives later, e.g. via an AJAX call, you'll need to call lazyLoadInstance.update(); to make LazyLoad check the DOM again. lazyLoadInstance.update(); lazy iFrame <iframe class="lazy" data-src="lazyFrame.html"></iframe>

    check if variable exists (is defined/initialized)

    this creates a switch in the page to turn on/off certain function if (typeof variable !== 'undefined') { if(typeof elem === 'string' && elem.trim()) { or elem != null showTopicNumber = true; if (typeof(showTopicNumber) !== 'undefined'){ if (showTopicNumber == true){ toc.append(topicNumber +' '+topic.html()+'
    '); }else{ toc.append(''+topic.html()+'
    '); } }else{ toc.append(''+topic.html()+'
    '); }

    HTML5 - Web SQL Database

    W3C no longer maintains this specification. The Web SQL Database API isn't actually part of the HTML5 specification but it is a separate specification which introduces a set of APIs to manipulate client-side databases using SQL.

    The Core Methods

    There are following three core methods defined in the spec that I am going to cover in this tutorial − openDatabase − This method creates the database object either using existing database or creating new one. transaction − This method gives us the ability to control a transaction and performing either commit or rollback based on the situation. executeSql − This method is used to execute actual SQL query.

    Opening Database

    The openDatabase method takes care of opening a database if it already exists, this method will create it if it already does not exist. To create and open a database, use the following code − var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); The above method took the following five parameters − Database name Version number Text description Size of database Creation callback The last and 5th argument, creation callback will be called if the database is being created. Without this feature, however, the databases are still being created on the fly and correctly versioned.

    Executing queries

    To execute a query you use the database.transaction() function. This function needs a single argument, which is a function that takes care of actually executing the query as follows − var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); db.transaction(function(tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)'); }); The above query will create a table called LOGS in 'mydb' database.

    INSERT Operation

    To create enteries into the table we add simple SQL query in the above example as follows − var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); db.transaction(function(tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")'); }); We can pass dynamic values while creating entering as follows − var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); db.transaction(function(tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)'); tx.executeSql('INSERT INTO LOGS (id,log) VALUES (?, ?'), [e_id, e_log]; }); Here e_id and e_log are external variables, and executeSql maps each item in the array argument to the "?"s.

    READ Operation

    To read already existing records we use a callback to capture the results as follows − var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); db.transaction(function(tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")'); }); db.transaction(function(tx) { tx.executeSql('SELECT * FROM LOGS', [], function(tx, results) { var len = results.rows.length, i; msg = "<p>Found rows: " + len + "</p>"; document.querySelector('#status').innerHTML += msg; for (i = 0; i < len; i++) { alert(results.rows.item(i).log ); } }, null); });

    Final Example

    So finally, let us keep this example in a full-fledged HTML5 document as follows and try to run it with Safari browser. Live Demo <!DOCTYPE HTML> <html> <head> <script type = "text/javascript"> var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); var msg; db.transaction(function(tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")'); tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")'); msg = '<p>Log message created and row inserted.</p>'; document.querySelector('#status').innerHTML = msg; }) db.transaction(function(tx) { tx.executeSql('SELECT * FROM LOGS', [], function(tx, results) { var len = results.rows.length, i; msg = "<p>Found rows: " + len + "</p>"; document.querySelector('#status').innerHTML += msg; for (i = 0; i < len; i++) { msg = "<p><b>" + results.rows.item(i).log + "</b></p>"; document.querySelector('#status').innerHTML += msg; } }, null); }); </script> </head> <body> <div id = "status" name = "status">Status Message</div> </body> </html> This will produce the following result − Log message created and row inserted. Found rows: 2 foobar logmsg

    Define a Function

    1 Define a Function. 2 Parameters vs. Arguments. 3 Invoking a Function. 4 Function Return. 5 Function Objects. 6 Key Takeaways.

    Define a Function.

    There are a few different ways to define a function in JavaScript: A Function Declaration defines a named function. To create a function declaration you use the function keyword followed by the name of the function. When using function declarations, the function definition is hoisted, thus allowing the function to be used before it is defined. function name(parameters){ statements} A Function Expressions defines a named or anonymous function. An anonymous function is a function that has no name. Function Expressions are not hoisted, and therefore cannot be used before they are defined. In the example below, we are setting the anonymous function object equal to a variable. let name = function(parameters){ statements } An Arrow Function Expression is a shorter syntax for writing function expressions. Arrow functions do not create their own this value. let name = (parameters) => { statements }

    Parameters vs. Arguments.

    If you’re new to JavaScript, you may have heard the terms parameters and arguments used interchangeably. While very similar, there is an important distinction to make between these two keywords. Parameters are used when defining a function, they are the names created in the function definition. In fact, during a function definition, we can pass in up to 255 parameters! Parameters are separated by commas in the (). Here’s an example with two parameters — param1 & param2: const param1 = true; const param2 = false; function twoParams(param1, param2){ console.log(param1, param2);} Arguments, on the other hand, are the values the function receives from each parameter when the function is executed (invoked). In the above example, our two arguments are true & false.

    Invoking a Function.

    Functions execute when the function is called. This process is known as invocation. You can invoke a function by referencing the function name, followed by an open and closed parenthesis: (). Lets explore an example. First, we’ll define a function named logIt. This function will take one parameter, name. When executed, the function will log that name back to the console: function logIt(name){ console.log(name);} To invoke our function, we call it, while passing in the singular parameter. Here I am calling this function with the name Joe: logIt('Joe'); // Joe If your function has no parameters, you can invoke it with an empty set of parenthesis: function logIt2(){ console.log('The second one');} logIt2(); // The second one

    Function Return.

    Every function in JavaScript returns undefined unless otherwise specified. Let’s test this by creating and invoking an empty function: function test(){}; test(); // undefined Awesome, as expected, undefined is returned. Now, we can customize what is returned in our function by using the return keyword followed by our return value. Take a look at the code below: function test(){ return true; }; test(); // true In this example we explicitly tell the function to return true. When we invoke the function, that’s exactly what happens. But why is this important? It’s important because the value that a function returns, is actually returned to the caller of the function. Take a look at this code: let double = function(num) { return num * 2; } This is a function expression that creates a function that will return two times the value of our input parameter num. We can then invoke the function and save the return value to a variable: let test = double(3); When we log out our test value, we get 6: console.log(test); // 6 Awesome! The return variable not only returns values from a function, but it assigns them to whatever called the function! Another important rule of the return statement is that it stops function execution immediately. Consider this example where we have two return statements in our test function: function test(){ return true; return false; }; test(); // true The first return statement immediately stops execution of our function and causes our function to return true. The code on line three: return false; is never executed.

    Function Objects.

    Functions are function objects. In JavaScript, anything that is not a primitive type ( undefined, null,boolean, number, or string) is an object. Objects in JavaScript are extremely versatile. Because of this, we can even pass a function as a parameter into another function. When a function accepts another function as a parameter, or returns a function, it is called a higher-order function. You’ve probably already used a bunch of higher order functions and don’t even know it: Array.prototype.mapand Array.prototype.filter are higher order functions (Just to name a couple). You can check out some of my previous articles to learn more about objects and higher order functions in JavaScript…

    Key Takeaways.

    This is a lot of information to digest. Here’s a list of the important stuff:
    • A function is a subprogram designed to perform a particular task.
    • Function definitions are hoisted — expressions are not.
    • Functions are executed when they are called. This is known as invoking a function.
    • Values can be passed into functions and used within the function. The name of the value is called a parameter. The actual value itself is called an argument.
    • Functions always return a value. In JavaScript, if no return value is specified, the function will return undefined by default.
    • Functions are objects.

    What is a Function Expression?

    A JavaScript function can also be defined using an expression. A function expression can be stored in a variable: var x = function(a, b) {return a * b}; After a function expression has been stored in a variable, the variable can be used as a function. Functions stored in variables do not need function names. They are always invoked (called) using the variable name.

    Function Expression VS. Function Statement

    Example: Function Expression alert(foo()); // ERROR! foo wasn't loaded yet var foo = function() { return 5; } Example: Function Declaration alert(foo()); // Alerts 5. Declarations are loaded before any code can run.
    function foo() { return 5; }
    Function declarations load before any code is executed while Function expressions load only when the interpreter reaches that line of code.Similar to the var statement, function declarations are hoisted to the top of other code. Function expressions aren’t hoisted, which allows them to retain a copy of the local variables from the scope where they were defined.

    Benefits of Function Expressions

    There are several different ways that function expressions become more useful than function declarations.

    "use strict"

    Defines that JavaScript code should be executed in "strict mode". With strict mode, you can not, for example, use undeclared variables. "use strict"; x = 3.14; // This will cause an error (x is not defined). "use strict"; myFunction(); function myFunction() { y = 3.14; // This will also cause an error because y is not declared } Declared inside a function, it has local scope (only the code inside the function is in strict mode): x = 3.14; // This will not cause an error. myFunction(); function myFunction() { "use strict"; y = 3.14; // This will cause an error } Why Strict Mode? Strict mode makes it easier to write "secure" JavaScript. Strict mode changes previously accepted "bad syntax" into real errors. As an example, in normal JavaScript, mistyping a variable name creates a new global variable. In strict mode, this will throw an error, making it impossible to accidentally create a global variable. In normal JavaScript, a developer will not receive any error feedback assigning values to non-writable properties. In strict mode, any assignment to a non-writable property, a getter-only property, a non-existing property, a non-existing variable, or a non-existing object, will throw an error.

    Calculate the Max/Min value from an array

    The built-in functions Math.max() and Math.min() find the maximum and minimum value of the arguments, respectively. Math.max(1, 2, 3, 4); // 4 Math.min(1, 2, 3, 4); // 1 These functions will not work as-is with arrays of numbers. However, there are some ways around this. var numbers = [1, 2, 3, 4]; Math.max.apply(null, numbers) // 4 Math.min.apply(null, numbers) // 1 A simpler way is with the new spread operator. var numbers = [1, 2, 3, 4]; Math.max(...numbers) // 4 Math.min(...numbers) // 1 This operator spread the values into the function.

    subtopic.js

    subtopic.js not yet finished

    load json from url

    $.getJSON(url, function(data) { //data is the JSON string });

    Append <script></script> in javascript

    <script src="http://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?_var=kline_monthqfq¶m=hk00700,month,,,320,qfq"></script> <script> console.log(kline_monthqfq); </script> var s = document.createElement("script"); s.type = "text/javascript"; s.src = "http://somedomain.com/somescript"; $("head").append(s); Note that the script will load and you can access the variables inside it, but you wouldn't see the actual <script> tag in the DOM.

    PhantomJS

    PhantomJS - Scriptable Headless Browser phantomjs documentation Quick Start with PhantomJS PhantomJS is a JS console. similar to nodejs must go to phantomjs install folder, and then run it from the terminal or command prompt: cd D:/phantomjs/bin/ phantomjs hello.js the file must inside the install folder very important to call phantom.exit at some point in the script, otherwise PhantomJS will not be terminated at all. Page Loading A web page can be loaded, analyzed, and rendered by creating a webpage object. The following script demonstrates the simplest use of page object. It loads example.com and then saves it as an image, example.png in the same directory the script was run in. var page = require('webpage').create(); page.open('http://example.com', function(status) { console.log("Status: " + status); if(status === "success") { page.render('example.png'); } phantom.exit(); }); Because of its rendering features, PhantomJS can be used to capture web pages, essentially taking a screenshot of the contents. The following loadspeed.js script loads a specified URL (do not forget the http protocol) and measures the time it takes to load it. var page = require('webpage').create(), system = require('system'), t, address; if (system.args.length === 1) { console.log('Usage: loadspeed.js [some URL]'); phantom.exit(); } t = Date.now(); address = system.args[1]; page.open(address, function(status) { if (status !== 'success') { console.log('FAIL to load the address'); } else { t = Date.now() - t; console.log('Loading ' + system.args[1]); console.log('Loading time ' + t + ' msec'); } phantom.exit(); }); Run the script with the command: phantomjs loadspeed.js http://www.google.com It outputs something like: Loading http://www.google.com Loading time 719 msec Code Evaluation To evaluate JavaScript code in the context of the web page, use evaluate() function. The execution is "sandboxed", there is no way for the code to access any JavaScript objects and variables outside its own page context. An object can be returned from evaluate(), however it is limited to simple objects and can’t contain functions or closures. Here is an example to show the title of a web page: var page = require('webpage').create(); page.open(url, function(status) { var title = page.evaluate(function() { return document.title; }); console.log('Page title is ' + title); phantom.exit(); }); Any console message from a web page, including from the code inside evaluate(), will not be displayed by default. To override this behavior, use the onConsoleMessage callback. The previous example can be rewritten to: var page = require('webpage').create(); page.onConsoleMessage = function(msg) { console.log('Page title is ' + msg); }; page.open(url, function(status) { page.evaluate(function() { console.log(document.title); }); phantom.exit(); }); Since the script is executed as if it is running on a web browser, standard DOM scripting and CSS selectors work just fine. It makes PhantomJS suitable to carry out various page automation tasks.

    Sine Wave in JavaScript

    Draw a Sine Wave in JavaScript JS Sine Wave

    single line 'if' statement syntax

    if (lemons) document.write("foo gave me a bar"); (lemons) ? alert("please give me a lemonade") : alert("then give me a beer"); (lemon) ? document.write("foo gave me a bar") : document.write("FALSE"); if(dog) alert('bark bark');

    if-else shorthand omitting the second expression

    if (x==2) doSomething; else doSomethingElse if (myArray[i].value) alert('yay') ; else continue;

    calculate ema

    function EMACalc(mArray,mRange) { var k = 2/(mRange + 1); // first item is just the same as the first item in the input emaArray = [mArray[0]]; // for the rest of the items, they are computed with the previous one for (var i = 1; i < mArray.length; i++) { emaArray.push(mArray[i] * k + emaArray[i - 1] * (1 - k)); } return emaArray; }

    remove empty element in an array

    var array = [0, 1, null, 2, "", 3, undefined, 3,,,,,, 4,, 4,, 5,, 6,,,,]; var filtered = array.filter(function(el) { return el != null; }); alert(filtered); or arr = arr.filter((val) => val != "");

    remove common items from list

    Use the Array.filter() method: fmList = [1,2,3,4,6,7,8,9] toRemove = [2,3,5] fmList = fmList.filter( function( item ) { return !toRemove.includes( item ); } ); fmList = fmList.filter( ( item ) => !toRemove.includes( item ) );

    create script element and load it

    document.createElement(“script”) synchronously create <script> element with an "onload" handler, and that will be called when the script has been loaded and evaluated by the browser. var script = document.createElement('script'); script.onload = function() { alert("Script loaded and ready"); }; script.src = "http://whatever.com/the/script.js"; document.getElementsByTagName('head')[0].appendChild(script); This isn't pretty, but it works: <script type="text/javascript"> document.write('<script type="text/javascript" src="other.js"></script>'); </script> <script type="text/javascript"> functionFromOther(); </script> Or <script type="text/javascript"> document.write('<script type="text/javascript" src="other.js"></script>'); window.onload = function() { functionFromOther(); }; </script> another way: var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.async=true; g.src=u+'m.js'; s.parentNode.insertBefore(g, s);

    JSON methods, toJSON

    Let’s say we have a complex object, and we’d like to convert it into a string, to send it over a network, or just to output it for logging purposes. let user = { name: "John", age: 30, toString() { return `{name: "${this.name}", age: ${this.age}}`; } }; alert(user); // {name: "John", age: 30} …But in the process of development, new properties are added, old properties are renamed and removed. Updating such toString every time can become a pain. JavaScript provides methods: JSON.stringify to convert objects into JSON. JSON.parse to convert JSON back into an object. For instance, here we JSON.stringify a student: let student = { name: 'John', age: 30, isAdmin: false, courses: ['html', 'css', 'js'], wife: null }; let json = JSON.stringify(student); alert(typeof json); // we've got a string! alert(json); /* JSON-encoded object: { "name": "John", "age": 30, "isAdmin": false, "courses": ["html", "css", "js"], "wife": null } */ The method JSON.stringify(student) takes the object and converts it into a string. The resulting json string is called a JSON-encoded or serialized or stringified or marshalled object. We are ready to send it over the wire or put into a plain data store. Please note that a JSON-encoded object has several important differences from the object literal: Strings use double quotes. No single quotes or backticks in JSON. So 'John' becomes "John". Object property names are double-quoted also. That’s obligatory. So age:30 becomes "age":30. JSON.stringify can be applied to primitives as well. JSON supports following data types: Objects { ... } Arrays [ ... ] Primitives: strings, numbers, boolean values true/false, null. For instance: // a number in JSON is just a number alert( JSON.stringify(1) ) // 1 // a string in JSON is still a string, but double-quoted alert( JSON.stringify('test') ) // "test" alert( JSON.stringify(true) ); // true alert( JSON.stringify([1, 2, 3]) ); // [1,2,3] JSON is data-only language-independent specification, so some JavaScript-specific object properties are skipped by JSON.stringify. Namely: Function properties (methods). Symbolic properties. Properties that store undefined. let user = { sayHi() { // ignored alert("Hello"); }, [Symbol("id")]: 123, // ignored something: undefined // ignored }; alert( JSON.stringify(user) ); // {} (empty object) Usually that’s fine. If that’s not what we want, then soon we’ll see how to customize the process. The great thing is that nested objects are supported and converted automatically. For instance: let meetup = { title: "Conference", room: { number: 23, participants: ["john", "ann"] } }; alert( JSON.stringify(meetup) ); /* The whole structure is stringified: { "title":"Conference", "room":{"number":23,"participants":["john","ann"]}, } */ The important limitation: there must be no circular references. For instance: let room = { number: 23 }; let meetup = { title: "Conference", participants: ["john", "ann"] }; meetup.place = room; // meetup references room room.occupiedBy = meetup; // room references meetup JSON.stringify(meetup); // Error: Converting circular structure to JSON Here, the conversion fails, because of circular reference: room.occupiedBy references meetup, and meetup.place references room:

    Excluding and transforming: replacer

    The full syntax of JSON.stringify is: let json = JSON.stringify(value[, replacer, space])
    value
    A value to encode.
    replacer
    Array of properties to encode or a mapping function function(key, value).
    space
    Amount of space to use for formatting
    Most of the time, JSON.stringify is used with the first argument only. But if we need to fine-tune the replacement process, like to filter out circular references, we can use the second argument of JSON.stringify. If we pass an array of properties to it, only these properties will be encoded. For instance: let room = { number: 23 }; let meetup = { title: "Conference", participants: [{name: "John"}, {name: "Alice"}], place: room // meetup references room }; room.occupiedBy = meetup; // room references meetup alert( JSON.stringify(meetup, ['title', 'participants']) ); // {"title":"Conference","participants":[{},{}]} Here we are probably too strict. The property list is applied to the whole object structure. So the objects in participants are empty, because name is not in the list. Let’s include in the list every property except room.occupiedBy that would cause the circular reference: let room = { number: 23 }; let meetup = { title: "Conference", participants: [{name: "John"}, {name: "Alice"}], place: room // meetup references room }; room.occupiedBy = meetup; // room references meetup alert( JSON.stringify(meetup, ['title', 'participants', 'place', 'name', 'number']) ); /* { "title":"Conference", "participants":[{"name":"John"},{"name":"Alice"}], "place":{"number":23} } */ Now everything except occupiedBy is serialized. But the list of properties is quite long. Fortunately, we can use a function instead of an array as the replacer. The function will be called for every (key, value) pair and should return the “replaced” value, which will be used instead of the original one. Or undefined if the value is to be skipped. In our case, we can return value “as is” for everything except occupiedBy. To ignore occupiedBy, the code below returns undefined: let room = { number: 23 }; let meetup = { title: "Conference", participants: [{name: "John"}, {name: "Alice"}], place: room // meetup references room }; room.occupiedBy = meetup; // room references meetup alert( JSON.stringify(meetup, function replacer(key, value) { alert(`${key}: ${value}`); return (key == 'occupiedBy') ? undefined : value; })); /* key:value pairs that come to replacer: : [object Object] title: Conference participants: [object Object],[object Object] 0: [object Object] name: John 1: [object Object] name: Alice place: [object Object] number: 23 */ Please note that replacer function gets every key/value pair including nested objects and array items. It is applied recursively. The value of this inside replacer is the object that contains the current property. The first call is special. It is made using a special “wrapper object”: {": meetup}. In other words, the first (key, value) pair has an empty key, and the value is the target object as a whole. That’s why the first line is ":[object Object]" in the example above. The idea is to provide as much power for replacer as possible: it has a chance to analyze and replace/skip even the whole object if necessary.

    Formatting: space

    The third argument of JSON.stringify(value, replacer, space) is the number of spaces to use for pretty formatting. Previously, all stringified objects had no indents and extra spaces. That’s fine if we want to send an object over a network. The space argument is used exclusively for a nice output. Here space = 2 tells JavaScript to show nested objects on multiple lines, with indentation of 2 spaces inside an object: let user = { name: "John", age: 25, roles: { isAdmin: false, isEditor: true } }; alert(JSON.stringify(user, null, 2)); /* two-space indents: { "name": "John", "age": 25, "roles": { "isAdmin": false, "isEditor": true } } */ /* for JSON.stringify(user, null, 4) the result would be more indented: { "name": "John", "age": 25, "roles": { "isAdmin": false, "isEditor": true } } */ The space parameter is used solely for logging and nice-output purposes.

    Custom “toJSON”

    Like toString for string conversion, an object may provide method toJSON for to-JSON conversion. JSON.stringify automatically calls it if available. For instance: let room = { number: 23 }; let meetup = { title: "Conference", date: new Date(Date.UTC(2017, 0, 1)), room }; alert( JSON.stringify(meetup) ); /* { "title":"Conference", "date":"2017-01-01T00:00:00.000Z", // (1) "room": {"number":23} // (2) } */ Here we can see that date (1) became a string. That’s because all dates have a built-in toJSON method which returns such kind of string. Now let’s add a custom toJSON for our object room (2): let room = { number: 23, toJSON() { return this.number; } }; let meetup = { title: "Conference", room }; alert( JSON.stringify(room) ); // 23 alert( JSON.stringify(meetup) ); /* { "title":"Conference", "room": 23 } */ As we can see, toJSON is used both for the direct call JSON.stringify(room) and when room is nested in another encoded object.

    JSON.parse

    To decode a JSON-string, we need another method named JSON.parse. The syntax: let value = JSON.parse(str, [reviver]);
    str
    JSON-string to parse.
    reviver
    Optional function(key,value) that will be called for each (key, value) pair and can transform the value.
    For instance: // stringified array let numbers = "[0, 1, 2, 3]"; numbers = JSON.parse(numbers); alert( numbers[1] ); // 1 Or for nested objects: let userData = '{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }'; let user = JSON.parse(userData); alert( user.friends[1] ); // 1 The JSON may be as complex as necessary, objects and arrays can include other objects and arrays. But they must obey the same JSON format. Here are typical mistakes in hand-written JSON (sometimes we have to write it for debugging purposes): let json = `{ name: "John", // mistake: property name without quotes "surname": 'Smith', // mistake: single quotes in value (must be double) 'isAdmin': false // mistake: single quotes in key (must be double) "birthday": new Date(2000, 2, 3), // mistake: no "new" is allowed, only bare values "friends": [0,1,2,3] // here all fine }`; Besides, JSON does not support comments. Adding a comment to JSON makes it invalid. There’s another format named JSON5, which allows unquoted keys, comments etc. But this is a standalone library, not in the specification of the language. The regular JSON is that strict not because its developers are lazy, but to allow easy, reliable and very fast implementations of the parsing algorithm.

    Using reviver

    Imagine, we got a stringified meetup object from the server. It looks like this: // title: (meetup title), date: (meetup date) let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; …And now we need to deserialize it, to turn back into JavaScript object. Let’s do it by calling JSON.parse: let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; let meetup = JSON.parse(str); alert( meetup.date.getDate() ); // Error! Whoops! An error! The value of meetup.date is a string, not a Date object. How could JSON.parse know that it should transform that string into a Date? Let’s pass to JSON.parse the reviving function as the second argument, that returns all values “as is”, but date will become a Date: let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; let meetup = JSON.parse(str, function(key, value) { if (key == 'date') return new Date(value); return value; }); alert( meetup.date.getDate() ); // now works! By the way, that works for nested objects as well: let schedule = `{ "meetups": [ {"title":"Conference","date":"2017-11-30T12:00:00.000Z"}, {"title":"Birthday","date":"2017-04-18T12:00:00.000Z"} ] }`; schedule = JSON.parse(schedule, function(key, value) { if (key == 'date') return new Date(value); return value; }); alert( schedule.meetups[1].date.getDate() ); // works!

    Summary

    JSON is a data format that has its own independent standard and libraries for most programming languages. JSON supports plain objects, arrays, strings, numbers, booleans, and null. JavaScript provides methods JSON.stringify to serialize into JSON and JSON.parse to read from JSON. Both methods support transformer functions for smart reading/writing. If an object has toJSON, then it is called by JSON.stringify.

    Tasks

    Turn the object into JSON and back

    importance: 5Turn the user into JSON and then read it back into another variable. let user = { name: "John Smith", age: 35 }; let user = { name: "John Smith", age: 35 }; let user2 = JSON.parse(JSON.stringify(user));

    importance: 5In simple cases of circular references, we can exclude an offending property from serialization by its name. But sometimes we can’t just use the name, as it may be used both in circular references and normal properties. So we can check the property by its value. Write replacer function to stringify everything, but remove properties that reference meetup: let room = { number: 23 }; let meetup = { title: "Conference", occupiedBy: [{name: "John"}, {name: "Alice"}], place: room }; // circular references room.occupiedBy = meetup; meetup.self = meetup; alert( JSON.stringify(meetup, function replacer(key, value) { /* your code */ })); /* result should be: { "title":"Conference", "occupiedBy":[{"name":"John"},{"name":"Alice"}], "place":{"number":23} } */ let room = { number: 23 }; let meetup = { title: "Conference", occupiedBy: [{name: "John"}, {name: "Alice"}], place: room }; room.occupiedBy = meetup; meetup.self = meetup; alert( JSON.stringify(meetup, function replacer(key, value) { return (key != " && value == meetup) ? undefined : value; })); /* { "title":"Conference", "occupiedBy":[{"name":"John"},{"name":"Alice"}], "place":{"number":23} } */

    show turnover on page

    function showTO(stkcode) { stkcode = "00000"+stkcode codewidth = stkcode.length stkcode = stkcode.slice(codewidth-5, codewidth) urladdr = 'http://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?_var=kline_dayqfq&param=hk' + stkcode + ',day,,,20,qfq'; var script = document.createElement('script'); script.onload = function() { $("#turnover").html("Turnover: "); theObj = kline_dayqfq.data; newObj = Object.values(theObj) newObj = Object.values(newObj[0]) newObj = Object.values(newObj[0]) for(i=10;i<newObj.length;i++){ thedate = newObj[i][0] // date theamt = Math.round(Number(newObj[i][8])) // amt $("#turnover").append( theamt,"w ") } }; script.src = urladdr; document.getElementsByTagName('head')[0].appendChild(script); }

    get the name of the array in json data

    let user = { name: "John", age: 30 }; Object.keys(user) = ["name", "age"] Object.values(user) = ["John", 30] Object.entries(user) = [ ["name","John"], ["age",30] ] Accessing nested JSON values with unknown names https://stackoverflow.com/questions/36031009/access-elements-inside-json-object-without-knowing-names

    navigation methods

    if(testkey == 'T'){window.scrollTo(0,0);} if(testkey == '8'){window.location = '#dateTime';} if(testkey == "2"){ divtoc = document.getElementById("toc"); $('body,html').animate({scrollTop:(divtoc.clientHeight + divtoc.offsetTop-600)}, 1); }

    detect whether the "ALT" key was pressed

    event.altKey A Boolean, indicating whether the "ALT" key was pressed when the key event occured. document.onkeydown = keydown; function keydown(evt) { if (!evt) evt = event; if (evt.altKey) { alert('alt'); } } or $(document).on('keydown', function(e) { if (e.key === 'Alt') { alert('alt'); } });

    Style Object Properties

    Sets or returns the Object Properties example thePointerImg.style.width = (currWidth - 100) + "px"; thePointerImg.style.transform = "rotate(90deg)"; Rotate and translate transform-origin: left; translate(50%, 50%) rotate(90deg) ; transform-origin: 50%; rotate(90deg) translateY(100%) ; Be careful on the "order of execution" in CSS3 chains! The rule is (right) from (left). Not Left to Right. transformation: translate(0,10%) rotate(25deg); The "rotate" operation is done first, than the "translate" operation comes next/second. alignContent alignment between the lines inside a flexible container when the items do not use all available space alignItems alignment for items inside a flexible container alignSelf alignment for selected items inside a flexible container animation A shorthand property for all the animation properties below, except the animationPlayState property animationDelay when the animation will start animationDirection whether or not the animation should play in reverse on alternate cycles animationDuration how many seconds or milliseconds an animation takes to complete one cycle animationFillMode what values are applied by the animation outside the time it is executing animationIterationCount number of times an animation should be played animationName a name for the @keyframes animation animationTimingFunction speed curve of the animation animationPlayState whether the animation is running or paused background all the background properties in one declaration backgroundAttachment whether a background-image is fixed or scrolls with the page backgroundColor background-color of an element backgroundImage background-image for an element backgroundPosition starting position of a background-image backgroundRepeat how to repeat (tile) a background-image backgroundClip painting area of the background backgroundOrigin positioning area of the background images backgroundSize size of the background image backfaceVisibility whether or not an element should be visible when not facing the screen border borderWidth, borderStyle, and borderColor in one declaration borderBottom all the borderBottom properties in one declaration borderBottomColor color of the bottom border borderBottomLeftRadius shape of the border of the bottom-left corner borderBottomRightRadius shape of the border of the bottom-right corner borderBottomStyle style of the bottom border borderBottomWidth width of the bottom border borderCollapse whether the table border should be collapsed into a single border, or not borderColor color of an element's border (can have up to four values) borderImage A shorthand property for setting or returning all the borderImage properties borderImageOutset amount by which the border image area extends beyond the border box borderImageRepeat whether the image-border should be repeated, rounded or stretched borderImageSlice inward offsets of the image-border borderImageSource image to be used as a border borderImageWidth widths of the image-border borderLeft all the borderLeft properties in one declaration borderLeftColor color of the left border borderLeftStyle style of the left border borderLeftWidth width of the left border borderRadius A shorthand property for setting or returning all the four borderRadius properties borderRight all the borderRight properties in one declaration borderRightColor color of the right border borderRightStyle style of the right border borderRightWidth width of the right border borderSpacing space between cells in a table borderStyle style of an element's border (can have up to four values) borderTop all the borderTop properties in one declaration borderTopColor color of the top border borderTopLeftRadius shape of the border of the top-left corner borderTopRightRadius shape of the border of the top-right corner borderTopStyle style of the top border borderTopWidth width of the top border borderWidth width of an element's border (can have up to four values) bottom bottom position of a positioned element boxDecorationBreak behaviour of the background and border of an element at page-break, or, for in-line elements, at line-break. boxShadow Attaches one or more drop-shadows to the box boxSizing Allows you to define certain elements to fit an area in a certain way captionSide position of the table caption clear position of the element relative to floating objects clip which part of a positioned element is visible color color of the text columnCount number of columns an element should be divided into columnFill how to fill columns columnGap gap between the columns columnRule A shorthand property for setting or returning all the columnRule properties columnRuleColor color of the rule between columns columnRuleStyle style of the rule between columns columnRuleWidth width of the rule between columns columns A shorthand property for setting or returning columnWidth and columnCount columnSpan how many columns an element should span across columnWidth width of the columns content Used with the :before and :after pseudo-elements, to insert generated content counterIncrement Increments one or more counters counterReset Creates or resets one or more counters cursor type of cursor to display for the mouse pointer direction text direction display an element's display type emptyCells whether to show the border and background of empty cells, or not filter image filters (visual effects, like blur and saturation) flex length of the item, relative to the rest flexBasis initial length of a flexible item flexDirection direction of the flexible items flexFlow A shorthand property for the flexDirection and the flexWrap properties flexGrow how much the item will grow relative to the rest flexShrink how the item will shrink relative to the rest flexWrap whether the flexible items should wrap or not cssFloat horizontal alignment of an element font fontStyle, fontVariant, fontWeight, fontSize, lineHeight, and fontFamily in one declaration fontFamily font family for text fontSize font size of the text fontStyle whether the style of the font is normal, italic or oblique fontVariant whether the font should be displayed in small capital letters fontWeight boldness of the font fontSizeAdjust Preserves the readability of text when font fallback occurs fontStretch Selects a normal, condensed, or expanded face from a font family hangingPunctuation Specifies whether a punctuation character may be placed outside the line box height height of an element hyphens Sets how to split words to improve the layout of paragraphs icon Provides the author the ability to style an element with an iconic equivalent imageOrientation Specifies a rotation in the right or clockwise direction that a user agent applies to an image isolation Defines whether an element must create a new stacking content justifyContent alignment between the items inside a flexible container when the items do not use all available space. left left position of a positioned element letterSpacing space between characters in a text lineHeight distance between lines in a text listStyle listStyleImage, listStylePosition, and listStyleType in one declaration listStyleImage an image as the list-item marker listStylePosition position of the list-item marker listStyleType list-item marker type margin margins of an element (can have up to four values) marginBottom bottom margin of an element marginLeft left margin of an element marginRight right margin of an element marginTop top margin of an element maxHeight maximum height of an element maxWidth maximum width of an element minHeight minimum height of an element minWidth minimum width of an element navDown where to navigate when using the arrow-down navigation key navIndex tabbing order for an element navLeft where to navigate when using the arrow-left navigation key navRight where to navigate when using the arrow-right navigation key navUp where to navigate when using the arrow-up navigation key objectFit Specifies how the contents of a replaced element should be fitted to the box established by its used height and width objectPosition Specifies the alignment of the replaced element inside its box opacity opacity level for an element order order of the flexible item, relative to the rest orphans minimum number of lines for an element that must be left at the bottom of a page when a page break occurs inside an element outline all the outline properties in one declaration outlineColor color of the outline around a element outlineOffset Offsets an outline, and draws it beyond the border edge outlineStyle style of the outline around an element outlineWidth width of the outline around an element overflow what to do with content that renders outside the element box overflowX Specifies what to do with the left/right edges of the content, if it overflows the element's content area overflowY Specifies what to do with the top/bottom edges of the content, if it overflows the element's content area padding padding of an element (can have up to four values) paddingBottom bottom padding of an element paddingLeft left padding of an element paddingRight right padding of an element paddingTop top padding of an element pageBreakAfter page-break behavior after an element pageBreakBefore page-break behavior before an element pageBreakInside page-break behavior inside an element perspective perspective on how 3D elements are viewed perspectiveOrigin bottom position of 3D elements position type of positioning method used for an element (static, relative, absolute or fixed) quotes type of quotation marks for embedded quotations resize whether or not an element is resizable by the user right right position of a positioned element tableLayout way to lay out table cells, rows, and columns tabSize length of the tab-character textAlign horizontal alignment of text textAlignLast how the last line of a block or a line right before a forced line break is aligned when text-align is "justify" textDecoration decoration of a text textDecorationColor color of the text-decoration textDecorationLine type of line in a text-decoration textDecorationStyle style of the line in a text decoration textIndent indentation of the first line of text textJustify justification method used when text-align is "justify" textOverflow what should happen when text overflows the containing element textShadow shadow effect of a text textTransform capitalization of a text top top position of a positioned element transform Applies a 2D or 3D transformation to an element transformOrigin position of transformed elements transform-origin transformStyle how nested elements are rendered in 3D space transition A shorthand property for setting or returning the four transition properties transitionProperty CSS property that the transition effect is for transitionDuration how many seconds or milliseconds a transition effect takes to complete transitionTimingFunction speed curve of the transition effect transitionDelay when the transition effect will start unicodeBidi whether the text should be overridden to support multiple languages in the same document userSelect whether the text of an element can be selected or not verticalAlign vertical alignment of the content in an element visibility whether an element should be visible whiteSpace how to handle tabs, line breaks and whitespace in a text width width of an element wordBreak line breaking rules for non-CJK scripts wordSpacing spacing between words in a text wordWrap Allows long, unbreakable words to be broken and wrap to the next line widows minimum number of lines for an element that must be visible at the top of a page zIndex stack order of a positioned element CSS 2D Transforms Methods Example div { transform: rotate(20deg); /* Standard syntax */ transform: translate(50px, 100px); transform: scale(2, 3); } translate(), rotate(), scaleX(), scaleY(), scale(), skewX(), skewY(), skew(), matrix() The matrix() method take six parameters, containing mathematic functions, which allows you to rotate, scale, move (translate), and skew elements. The parameters are as follow: matrix(scaleX(),skewY(),skewX(),scaleY(),translateX(),translateY()) Example transform: matrix(1, -0.3, 0, 1, 0, 0); matrix(n,n,n,n,n,n) transformation, using a matrix of six values translate(x,y) translation, moving the element along the X- and the Y-axis translateX(n) translation, moving the element along the X-axis translateY(n) translation, moving the element along the Y-axis scale(x,y) scale transformation, changing the elements width and height scaleX(n) scale transformation, changing the element's width scaleY(n) scale transformation, changing the element's height rotate(angle) rotation, the angle is specified in the parameter skew(x-angle,y-angle) skew transformation along the X- and the Y-axis skewX(angle) skew transformation along the X-axis skewY(angle) skew transformation along the Y-axis

    jQuery.getScript

    The jQuery.getScript() method is a shorthand of the Ajax function (with the dataType attribute: $.ajax({ url: url,dataType: "script"})) This needs testing! $.getScript("demo_script.js"); $.getScript("test.js", function(data, textStatus, jqxhr) { console.log(data); //data returned console.log(textStatus); //success console.log(jqxhr.status); //200 console.log('Load was performed.'); });

    document.getElementById vs jQuery $()

    Not exactly!! document.getElementById('contents'); //returns a HTML DOM Object var contents = $('#contents'); //returns a jQuery Object In jQuery, to get the same result as document.getElementById, you can access the jQuery Object and get the first element in the object (Remember JavaScript objects act similar to associative arrays). var contents = $('#contents')[0]; //returns a HTML DOM Object or this var contents = $('#contents').get(0); ============== Calling document.getElementById('id') will return a raw DOM object. Calling $('#id') will return a jQuery object that wraps the DOM object and provides jQuery methods. Thus, you can only call jQuery methods like css() or animate() on the $() call. You can also write $(document.getElementById('id')) which will return a jQuery object and is equivalent to $('#id'). You can get the underlying DOM object from a jQuery object by writing $('#id')[0].

    math

    Math.PI; // returns 3.141592653589793 Math.round(4.7); // returns 5 Math.round(4.4); // returns 4 Math.pow(8, 2); // returns 64 Math.sqrt(64); // returns 8 Math.abs(-4.7); // returns 4.7 Math.ceil(4.4); // returns 5 Math.floor(4.7); // returns 4 Math.sin(90 * Math.PI / 180); // returns 1 (the sine of 90 degrees) Math.cos(0 * Math.PI / 180); // returns 1 (the cos of 0 degrees) Math.min(0, 150, 30, 20, -8, -200); // returns -200 Math.max(0, 150, 30, 20, -8, -200); // returns 150 Math.random(); // returns a random number Math.E // returns Euler's number Math.PI // returns PI Math.SQRT2 // returns the square root of 2 Math.SQRT1_2 // returns the square root of 1/2 Math.LN2 // returns the natural logarithm of 2 Math.LN10 // returns the natural logarithm of 10 Math.LOG2E // returns base 2 logarithm of E Math.LOG10E // returns base 10 logarithm of E Math.js Examples Math.js is an extensive math library for JavaScript and Node.js. Work with different data types like numbers, big numbers, complex numbers, fractions, units, and matrices. Powerful and easy to use. Example // functions and constants math.round(math.e, 3) // 2.718 math.atan2(3, -3) / math.pi // 0.75 math.log(10000, 10) // 4 math.sqrt(-4) // 2i math.derivative('x^2 + x', 'x') // 2*x+1 math.pow([[-1, 2], [3, 1]], 2) // [[7, 0], [0, 7]] // expressions math.eval('1.2 * (2 + 4.5)') // 7.8 math.eval('12.7 cm to inch') // 5 inch math.eval('sin(45 deg) ^ 2') // 0.5 math.eval('9 / 3 + 2i') // 3 + 2i math.eval('det([-1, 2; 3, 1])') // -7 // chaining math.chain(3) .add(4) .multiply(2) .done() // 14 Demo Try the expression parser below. See Math Notepad for a full application. 1.2 / (3.3 + 1.7) 0.24 a = 5.08 cm + 2 inch 10.16 cm a to inch 4 inch sin(90 deg) 1 f(x, y) = x ^ y f(x, y) f(2, 3) 8 Evaluate Shortcut keys: Press S to set focus to the input field Press Ctrl+F11 to toggle full screen Enter "clear" to clear history derivative(expr, variable) derivative(expr, variable, options) Parameters Parameter Type Description expr Node | string The expression to differentiate variable SymbolNode | string The variable over which to differentiate options {simplify: boolean} There is one option available, simplify, which is true by default. When false, output will not be simplified. Returns# Examples math.derivative('x^2', 'x') // Node {2 * x} math.derivative('x^2', 'x', {simplify: false}) // Node {2 * 1 * x ^ (2 - 1) math.derivative('sin(2x)', 'x')) // Node {2 * cos(2 * x)} math.derivative('2*x', 'x').evaluate() // number 2 math.derivative('x^2', 'x').evaluate({x: 4}) // number 8 const f = math.parse('x^2') const x = math.parse('x') math.derivative(f, x) // Node {2 * x}

    physics

    Matter.js is a 2D physics engine PhysicsJS easy-to-use physics engine for javascript Build a simple 2D physics engine Planck.js 2D JavaScript physics engine

    chemistry

    Kekule.js open source JavaScript library for chemoinformatics

    Generate Alert Box if user tries to change text in text input field

    <FORM> <INPUT TYPE="text" VALUE= "dont change" NAME = "leavebutton" onChange= "alert('Please dont change this')"></INPUT> </FORM>

    Show the date and time when the page loads

    In this example the event handler onLoad is embedded within the tag. OnLoad activates whenever a new page has finished downloading. This alert code tells the browser to create an alert box containing the value of the variable "today". Thus, it automatically prints out the date and time when the page has finished loading and requires no special action by the user. ^lt;SCRIPT LANGUAGE = "Javascript"> var today= new Date() ^lt;/SCRIPT> .... <BODY onload=alert(today)>

    Animate the background color of a document

    Notice that the script is not just a series of document.bgColor = commands. You could write that script but the colors would change so quickly that you would not see the animated effect. We need to introduce a delay between each background color change. Javascript offers a setTimeout() method that allows creation of delays as well as serving other functions. The setTimeout() method requires two elements to be enclosed in its parentheses. The first element is an expression to be evaluated or acted upon. The second element is the number of milliseconds (thousandths of a second) to be waited before the first action is undertaken. setTimeout(expression to be evaluated, milliseconds) ^lt;SCRIPT LANGUAGE= "javascript"> setTimeout("document.bgColor='white'", 1000) setTimeout("document.bgColor='lightpink'", 1500) setTimeout("document.bgColor = 'pink'", 2000) setTimeout("document.bgColor = 'deeppink'", 2500) setTimeout("document.bgColor = 'red'", 3000) setTimeout("document.bgColor = 'tomato'", 3500) setTimeout("document.bgColor = 'darkred'", 4000) ^lt;/SCRIPT>

    User assignment of a property and dynamic generation of a Web page

    In the example, which illustrates user assigned properties, a new property is defined for the document object called firstline. Anytime Javascript encounters the expression document.firstline it will produce the assigned text. The fact that I named it "firstline" carries no special meaning to Javascript; that is, it does not know that it is to be the first line in the document. Generally, it is a good idea to name the properties with a name related to your intended use. The rest of the example shows how the write() method can be used to generate text that appears on a web page. Document.open() prepares for creating a page. The second open() forces it to appear. <HTML> <HEAD> ^lt;SCRIPT LANGUAGE = "Javascript"> document.firstline = "Welcome to this page" ^lt;/SCRIPT> <TITLE>load demo</TITLE> </HEAD> <BODY> ^lt;SCRIPT> document.open() document.write(document.firstline) document.open() ^lt;/SCRIPT> </BODY>

    Sample Script to Animate Text in Text Field

    This script will set up a form that asks for user input. It will animate text in boxes that surround it to urge the user to provide the information. To accomplish this, we must first use standard HTML form tags to create the input fields for user typing. We must also create text fields that we will use to create the animation. For the sake of illustrating methods of using Javascript to refer to different forms that appear on a page, the examples presents the information in 3 forms. It could have also been combined into one form. It places the fields for user input in the middle form called f2 and the fields that will animated text placed into them into fields f1 on top and f3 on the bottom. Also it places the input elements in form f1 and f3 into tables in order to gain more control over their placement. f1,f2, and f3 are just arbitrary names given to the fields. In this example "Answer Soon" text appears and disappears, moving around the fields from left to right on the top and then from left to right on the bottom. All the code to establish fields and tables should be famiilar to readers with HTML experience. The new part is the code enclosed in the SCRIPT tags. The heart of these commands are expressions that assign values to particular fields. For example the code line document.f1.ta1.value = 'Answer Soon' tells the browser to find the document object (the Web page) and then the form that is a subelement of it called f1 (the first one on top) and then the subelement of that form called ta.1 (the first text entry field). Once that element is targeted, the script tells the browser to change the value property of that text field by assigning it the text "Answer Soon". The Value attribute in standard HTML markup is the text that a field contains (usually because a user has typed it there.). Javascript has extended this allow the script to type values. To the user the text appears as in an animation. After text appears the sample script makes it disappear by assinging the blank value "" to the same text field. <HTML> <HEAD> <TITLE> Animated Text</TITLE> </HEAD> <BODY > <FORM NAME="f1"> <TABLE> <TR> <TD> <INPUT NAME="ta1" TYPE="text" SIZE="20"> </INPUT> <TD> <INPUT NAME="ta2" TYPE="text" SIZE="20"> </INPUT> <TD> <INPUT NAME="ta3" TYPE="text" SIZE="20"></INPUT> </TABLE></FORM> <FORM NAME="f2" ACTION="http://netadd.com/nam.cgi" METHOD="POST"> <CENTER> Name <INPUT NAME="pername" TYPE="text" SIZE="20"> Name</INPUT> Age <INPUT NAME="perage" TYPE="text" SIZE="5"> Age</INPUT> Occupation <INPUT NAME="perocc" TYPE="text" SIZE="20">Occupation </INPUT> <INPUT TYPE="Submit" VALUE="Submit"></INPUT> <INPUT TYPE="Reset" VALUE="Reset"></INPUT> </CENTER> </FORM> <FORM NAME="f3"> <TABLE> <TR> <TD> <INPUT NAME="ta4" TYPE="text" SIZE="20"> </INPUT> <TD> <INPUT NAME="ta5" TYPE="text" SIZE="20"> </INPUT> <TD> <INPUT NAME="ta6" TYPE="text" SIZE="20"></INPUT> </TABLE></FORM> ^lt;SCRIPT LANGUAGE= "javascript"> setTimeout("document.f1.ta1.value = 'Answer Soon'", 1000) setTimeout("document.f1.ta1.value = ''", 1300) setTimeout("document.f1.ta2.value = 'Answer Soon'", 1600) setTimeout("document.f1.ta2.value = ''", 1900) setTimeout("document.f1.ta3.value = 'Answer Soon'", 2200) setTimeout("document.f1.ta3.value = ''", 2500) setTimeout("document.f3.ta4.value = 'Answer Soon'", 2800) setTimeout("document.f3.ta4.value = ''", 3100) setTimeout("document.f3.ta5.value = 'Answer Soon'", 3400) setTimeout("document.f3.ta5.value = ''", 3700) setTimeout("document.f3.ta6.value = 'Answer Soon'", 4000) setTimeout("document.f3.ta6.value = ''", 4300) ^lt;/SCRIPT>

    Sample Script to Customize Links Based on User Button Choices

    This sample script demonstrates how to create a script that lets a user chose a category of infomation after which it dynamically generates an html page containing links relevant to that interest. It uses a simple form with radio buttons to determine interest. Just to add interest it also asks the users to type their name. Once the users are done chosing, they click on the submit button and the script generates the html document using their name. For the sake of clarity this example is very short with only one choice requested. The same principles, however, could be applied to more sophisticated sets ofchoices. There are three major parts to this Web page and script: A. Javascript script cotaining the database of links for each kind of music, the function to create a unique page based on their choice, and the function to create a new Netscape window to show the page. B. HTML code to create the informationrequest page cotaining an input form. C. Javascript code to set up default values. <HTML> <HEAD><TITLE>Choice</TITLE> ^lt;SCRIPT Language="javascript"> // sets up database of links - SECTION A1 muresources="" muresources["classical"]= "<A HREF='http://net.com/classical.file1'>Meditative classical music</A> <A HREF='http://net.com/classical.file2'>Provoking classical music</A>" muresources["rock"] = "<A HREF='http://net.com/rock.file1'>Popular rock music<A> <A HREF='http://net.com/rock.file2'>Exciting rock music</A>" muresources["ethnic"] = "<A HREF='http://net.com/mexican.file1'>Mexican music<A> <A HREF='http://net.com/Indian.file2'>Indian music</A>" function <o>getLink</o>() { // constructs unique page using name and choice of music - SECTION A.2 temp = muresources[choice] temp2 = "<TITLE>Custom Links</TITLE><H2>" +document.m.pername.value+", here are some links for you</H2><P>"+temp } function <o>writeIt</o>(){ // creates new window to display page - SECTION A.3 diswin = window.open(); diswin.document.open(); diswin.document.write(temp2); diswin.document.close() } function <o>doAll</o>(){ // master routine calls other functions - SECTION A.4 getLink(); writeIt() } ^lt;/SCRIPT> </HEAD> <BODY > <!-- Sets up basic input form SECTION B --> <H2> Choose the kind of music you prefer and this page will fetch links of interest to you</H2> <FORM NAME="m" > Choose a kind of music <INPUT TYPE="radio" NAME="mus" VALUE="classical" OnClick="choice='classical'" >Classical </INPUT> <INPUT TYPE="radio" NAME="mus" VALUE="rock" OnClick="choice='rock'">Rock</INPUT> <INPUT TYPE="radio" NAME="mus" VALUE="ethnic" OnClick="choice='ethnic'">Ethnic</INPUT> Please type your name <INPUT TYPE="text" NAME="pername" SIZE=25></INPUT> <INPUT TYPE="button" NAME="sub" VALUE="Show me links" OnClick=doAll()></INPUT> <INPUT TYPE="reset" NAME="res" ></INPUT> </FORM> ^lt;SCRIPT> // sets defaults - SECTION C choice = "classical" document.m.mus[0].checked = true document.m.mus[1].checked = false document.m.mus[2].checked = false ^lt;/SCRIPT> </BODY> </HTML>

    Using string properties to set characteristics of text on a page

    Several properties control the appearance of text on the page. Note, however, that they cannot control the appearance of text after the page is rendered. The document must be rewritten for the new characteristics to become visible. This example generates a series of lines, each with a different style,color, or size of text. ^lt;SCRIPT> //assigns value to variable test ="What is all this?" // opens document and uses methods to modify text characteristics document.open() document.write(test.bold()+"<P>") document.write(test.fontsize(7)+"<P>") document.write(test.fontcolor("red")+"<P>") document.write(test.toUpperCase()+"<P>") //assigns multiple characteristics to text document.write(test.italics().fontsize(6).fontcolor("green")+"<P>") document.open() ^lt;/SCRIPT>

    Using Substrings to Generate Scrolling Banners

    This example uses the subString method to create a scrolling banner in a text field and on the status line of the window. Scrolling text seems to slide from left to right. You can create this effect by systematically displaying a changing section of some target text. For example, if you display character 0 to 24 of some text and next display 1 to 25 and next 2 to 26, the text will appear to be moving from right to left. The sample illustrates a method for accomplishing this effect. <HTML> <HEAD><TITLE> Banner</TITLE> ^lt;SCRIPT LANGUAGE= "javascript"> // Puts the text to scroll into variable called sent - SECTION A // uses length propert to assess its length and put into variable slen // initalizes a,b,n, and subsent variables var sent = "This is a demonstration of a banner moving from the left to right. It makes use of the substring property of Javascript to make an interesting display" var slen = sent.length var siz = 25 var a = -3, b = 0 var subsent = "x" // Creates a function to capture substrings of sent - SECTION B function <o>makeSub</o>(a,b) { subsent = sent.substring(a,b) ; return subsent; } //Creates a function that increments the indexes of the substring - SECTION C //each time and calls the makeSub() function to geneate strings //a indicates start of substring and siz indicates size of string required function <o>newMake</o>() { a = a + 3; b = a + siz makeSub(a,b); return subsent } //function uses loop to get changing substrings of target - SECTION D //repeatedly calls newMake to get next substring //uses setTimeout() command to arrange for substrings to display // at specified times function <o>doIt</o>() { for (var i = 1; i <= slen ; i++) { setTimeout("document.z.textdisplay.value = newMake()", i*300); setTimeout("window.status = newMake()", i*300); } } ^lt;/SCRIPT> </HEAD> <BODY > <CENTER> <FORM NAME="z"> <INPUT NAME="textdisplay" TYPE="text" SIZE=25> </INPUT> <INPUT NAME="doit" Type="button" value = "Run Banner" onClick = "doIt()"> </INPUT> </FORM></CENTER> </BODY></HTML>

    load local file

    It will be blocked by CORS, only work with servers, ie files only online jQuery.get('http://localhost/foo.txt', function(data) { alert(data); }); Additionally, there's the new Fetch API: fetch("https://12Me21.github.io/test.txt") .then( response => response.text() ) .then( text => console.log(text) ) fetch('http://localhost/foo.txt') .then(response => response.text()) .then((data) => { console.log(data) } ) If you only want a constant string from the text file, you could include it as JavaScript: // This becomes the content of your foo.txt file let text = `My test text goes here!`; <script src="foo.txt"></script> <script> console.log(text); </script> When working with jQuery, instead of using jQuery.get, e.g. jQuery.get("foo.txt", undefined, function(data) { alert(data); }, "html").done(function() { alert("second success"); }).fail(function(jqXHR, textStatus) { alert(textStatus); }).always(function() { alert("finished"); }); you could use .load which gives you a much more condensed form: $("#myelement").load("foo.txt");

    webpack compile JavaScript

    uses uglify-js to minify JavaScript webpack optimizations webpack compile JavaScript modules

    Interesting libraries

    Realistic Water Ripple (Pixi.js) 3D Pikachu (Pixi.js) JavaScript Libraries 2020 Interesting libraries: Tesseract.js, Chart.js, Three.js, Anime.js, Howler.js, Reveal.js, Pixi.js, Video.js, Nipple.js, Intro.js, Faker.js, Editor.js, Popper.js,

    format number with leading zeros

    function pad(anum, size) { var stkcode = anum+""; while (stkcode.length < size) stkcode = "0" + stkcode; return stkcode; } function pad(num, size) { var stkcode = "000000000" + num; return stkcode.substr(stkcode.length-size); } stkcode = "00000"+stkcode codewidth = stkcode.length stkcode = stkcode.slice(codewidth-5, codewidth)

    Get column from a two dimensional array

    var twoDim = [[1,2,3],[4,5,6],[7,8,9]]; // take the third column var col3 = twoDim.map(function(value,index) { return value[2]; });

    filter() Method

    creates an array with elements that pass a test filter() does not change the original array. array.filter(function(currentValue, index, arr), thisValue) ages array that are 18 or over: var ages = [32, 33, 16, 40]; function checkAdult(age) { return age >= 18;} document.getElementById("demo").innerHTML = ages.filter(checkAdult); ages array that are a specific number or over: <input type="number" id="ageToCheck" value="18"> function checkAdult(age) { return age >= document.getElementById("ageToCheck").value; } document.getElementById("demo").innerHTML = ages.filter(checkAdult);

    Using Node-Osmosis with examples

    There are a number of options for web scraping in node.js, but my favorite library to work with is node-osmosis. To start, we'll do a simple single page scrape. We'll be working with this page on wikipedia, which contains population information for US States.

    1) Simple Page Scrape

    First, let's scrape some basic information from the page using basic selectors. osmosis .get(url) .set({ heading: 'h1', title: 'title' }) .data(item => console.log(item)); { heading: 'List of U.S. states and territories by population', title: 'List of U.S. states and territories by population - Wikipedia' }

    2) Scrape Using Find

    Next, let's say we want to get a list of all the states along with their populations. We can see that this data is in the first table on the page. In order to do this, we'll introduce a new function 'find', which sets the current context using selectors. Once we tell osmosis to select the rows from the first table, we can pick out the state and population values and pull them into an object. osmosis .get(url) .find('.wikitable:first tr:gt(0)') .set({ state: 'td[3]', population: 'td[4]' }) .data(item => console.log(item)); { state: 'California', population: '39,250,017' } { state: 'Texas', population: '27,862,596' } { state: 'Florida', population: '20,612,439' } { state: 'New York', population: '19,745,289' } { state: 'Illinois', population: '12,801,539' } { state: 'Pennsylvania', population: '12,784,227' } { state: 'Ohio', population: '11,646,273' } { state: 'Georgia', population: '10,310,371' } { state: 'North Carolina', population: '10,146,788' } { state: 'Michigan', population: '9,928,301' } ...

    3) Scrape Multiple Parts

    We can also use multiple set calls to pull out different pieces of data. osmosis .get(url) .set({ title: 'title' }) .find('.wikitable:first tr:gt(0)') .set({ state: 'td[3]', population: 'td[4]' }) .data(item => console.log(item)); { title: 'List of U.S. states and territories by population - Wikipedia', state: 'California', population: '39,250,017' } { title: 'List of U.S. states and territories by population - Wikipedia', state: 'Texas', population: '27,862,596' } { title: 'List of U.S. states and territories by population - Wikipedia', state: 'Florida', population: '20,612,439' } { title: 'List of U.S. states and territories by population - Wikipedia', state: 'New York', population: '19,745,289' } { title: 'List of U.S. states and territories by population - Wikipedia', state: 'Illinois', population: '12,801,539' } ...

    4) Following Links

    Now, let's say we wanted some information from each state. Osmosis has a follow function that we can use to scrape each state page. Since the URL is inside the table that we're scraping, we can pass that URL to the follow function using the a@href selector inside the 3rd column (td[3]). After we follow each page, we can use set again to pull data from each state page. In this example, we'll just pull out the longitude and latitude. The end result combines the elements from each 'set' call. osmosis .get(url) .find('.wikitable:first tr:gt(0)') .set({ state: 'td[3]', population: 'td[4]' }) .follow('td[3] a@href') .set({ longitude: '.longitude', latitude: '.latitude' }) .data(item => console.log(item)); { state: 'California', population: '39,250,017', longitude: '119°21'19"W', latitude: '35°27'31"N' } { state: 'Illinois', population: '12,801,539', longitude: '88°22'49"W', latitude: '41°16'42"N' } ...

    5) Promisification

    In all the examples above, we're just printing out each object as it's handled by the data function. Often times we want to return all of the data at once in an array. To do that, we can wrap the call in a Promise and add each element to an array as it's processed. function scrapePopulations() { return new Promise((resolve, reject) => { let results = []; osmosis .get(url) .find('.wikitable:first tr:gt(0)') .set({ state: 'td[3]', population: 'td[4]' }) .data(item => results.push(item)) .done(() => resolve(results)); }); } scrapePopulations().then(data => console.log(data)); // we can also get the same results more simply by wrapping the code with .set([]) osmosis .get(url) .set([ osmosis .find('.wikitable:first tr:gt(0)') .set({ state: 'td[3]', population: 'td[4]' }) ]) .data(items => console.log(items)) [{ state: 'California', population: '39,250,017' }, { state: 'Texas', population: '27,862,596' }, { state: 'Florida', population: '20,612,439' }, { state: 'New York', population: '19,745,289' }, { state: 'Illinois', population: '12,801,539' }, { state: 'Pennsylvania', population: '12,784,227' }, { state: 'Ohio', population: '11,646,273' }, { state: 'Georgia', population: '10,310,371' }, { state: 'North Carolina', population: '10,146,788' }, { state: 'Michigan', population: '9,928,301' }, { state: 'New Jersey', population: '8,944,469' }, { state: 'Virginia', population: '8,411,808' }, { state: 'Washington', population: '7,288,000' }, ...

    Creating a div element

    $('#parent').append('<div>hello</div>'); // or $('<div>hello</div>').appendTo('#parent'); d = document.createElement('div'); $(d).addClass(classname) .html(text) .appendTo($("#myDiv")) //main div .click(function() { $(this).remove();}) .hide() .slideToggle(300) .delay(2500) .slideToggle(300) .queue(function() { $(this).remove();}); $(document.createElement("div")) div = $("<div>").html("Loading......"); $("body").prepend(div); var customDiv = $("<div/>");

    Spread Operator

    ... are called spread attributes, it allows an expression to be expanded. var parts = ['two', 'three']; var numbers = ['one', ...parts, 'four', 'five']; // ["one", "two", "three", "four", "five"] use of spread operator:

    Concatenate arrays:

    shooter = ['Call', 'Cry', 'Evil']; Games = ['Speed', 'Gran', 'Burnout']; theGames = [...shooter, ...Games];  //["Call", "Cry", "Evil", "Speed", "Gran", "Burnout"]

    Destructuring an array:

    shooter = ['Call', 'Cry', 'Evil']; [first, ...remaining] = shooter; console.log(first); //Call console.log(remaining); //['Cry', 'Evil']

    Combining two objects:

    myCrush = { firstname: 'Selena', middlename: 'Marie' }; lastname = 'my last name'; myWife = { ...myCrush, lastname } // {firstname: 'Selena', // middlename: 'Marie', // lastname: 'my last name'}

    Rest Parameters

    another use for the three dots is known as Rest Parameters it take all the arguments to a function in as one array. Function arguments as array function fun1(...params) { }

    Alternative to apply()

    take a list of marks of top 5 students in a class. using the apply() method: myFun(m1, m2, m3, m4, m5) { // Do something } let marks = [10, 23, 83, -1, 92]; myFun(...marks);

    Using with Math Functions

    let mylist = [10, 23, 83, -1, 92, -33, 76, 29, 76, 100, 644, -633]; Math.max(...mylist); function doSum(...items) { let sum = 0; for (let item of items){ sum += item; } return sum; } doSum(1); doSum(1,2); doSum(1, 2, 3, 4); function doSum(times, ...items) { let sum = 0; for (let item of items){ sum += item*times; } return sum; } doSum(1, 1); doSum(2, 1, 2); doSum(3, 1, 2, 3); 1 6 18

    Dynamically load a JavaScript file

    write dynamic script tags: new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"}); The problem here is that we do not know when the external script file is fully loaded. We often want our dependant code on the very next line and like to write something like: if (iNeedSomeMore) { Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod(); myFancyMethod(); // cool, no need for callbacks! } There is a smart way to inject script dependencies without the need of callbacks. Simply pull the script via a synchronous AJAX request and eval the script on global level. If you use Prototype the Script.load method looks like this: var Script = { _loadedScripts: [], include: function(script) { // include script only once if (this._loadedScripts.include(script)) { return false; } // request file synchronous var code = new Ajax.Request(script, { asynchronous: false, method: "GET", evalJS: false, evalJSON: false }).transport.responseText; // eval code on global level if (Prototype.Browser.IE) { window.execScript(code); } else if (Prototype.Browser.WebKit) { $$("head").first().insert(Object.extend( new Element("script", { type: "text/javascript" }), { text: code } )); } else { window.eval(code); } // remember included script this._loadedScripts.push(script); } }; There is no import / include / require in javascript, but there are two main ways to achieve what you want: 1 - You can load it with an AJAX call then use eval. This is the most straightforward way but it's limited to your domain because of the Javascript safety settings, and using eval is opening the door to bugs and hacks. 2 - Add a script tag with the script URL in the HTML. Definitely the best way to go. You can load the script even from a foreign server, and it's clean as you use the browser parser to evaluate the code. You can put the tag in the head of the web page, or at the bottom of the body. Now, there is a big issue you must know about. Doing that implies that you remotely load the code. Modern web browsers will load the file and keep executing your current script because they load everything asynchronously to improve performances. It means that if you use these tricks directly, you won't be able to use your newly loaded code the next line after you asked it to be loaded, because it will be still loading. I used a much less complicated version recently with jQuery: <script src="scripts/jquery.js"></script> <script> var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"]; var $head = $("head"); for (var i = 0; i < js.length; i++) { $head.append("<script src=\"" + js[i] + "\"></scr" + "ipt>"); } </script> Update: jQuery-less version: <script> var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"]; for (var i = 0, l = js.length; i < l; i++) { document.getElementsByTagName("head")[0].innerHTML += ("<script src=\"" + js[i] + "\"></scr" + "ipt>"); } </script> another awesome answer $.getScript("my_lovely_script.js", function(){ alert("Script loaded and executed."); // here you can use anything you defined in the loaded script });

    dateAndTime function

    <span id="dateAndTime" onclick="showDateAndTime()"><script>showDateAndTime();</script></span> <h2>some weixin scripts</h2> window.logs = { pagetime: {} }; window.logs.pagetime['html_begin'] = (+new Date()); window.LANG= "en"; window.isOldVideoPage = false; var e=t.match(/http(?:s)?://([^/]+?)(/|$)/); if(e&&!/qq\.com(\:8080)?$/.test(e[1])&&!/weishi\.com$/.test(e[1]))return!0; ishttp=0==location.href.indexOf("http://"); String.prototype.html = function(encode) { var replace =["'", "'", """, '"', " ", " ", ">", ">", "<", "<", "¥", "¥", "&", "&"]; var replaceReverse = ["&", "&", "¥", "¥", "<", "<", ">", ">", " ", " ", '"', """, "'", "'"]; window.addEventListener('beforeunload', reportResLoadTime, false); window.addEventListener('unload', reportResLoadTime, false);

    set unique

    var visitedList = [4,5,4,6,3,4,5,2,23,1,4,4,4] var visitedList = Array.from(new Set(visitedList)) Sets are object type creating collections of unique values a few methods like add, size, has, forEach, delete and clear are available

    Sets

    Sets are object creating collections of unique values. The values in a set can be either simple primitives like strings or integers as well as more complex object types like object literals or arrays. Here’s a simple example showing off a basic set and a few of the available methods on it like add, size, has, forEach, delete and clear: let animals = new Set(); animals.add('🐷'); animals.add('🐼'); animals.add('🐢'); animals.add('🐿'); console.log(animals.size); // 4 animals.add('🐼'); console.log(animals.size); // 4 console.log(animals.has('🐷')); // true animals.delete('🐷'); console.log(animals.has('🐷')); // false animals.forEach(animal => { console.log(`Hey ${animal}!`); }); // Hey 🐼! // Hey 🐢! // Hey 🐿! animals.clear(); console.log(animals.size); // 0 Here’s another example where we pass-in an array to initialize the set. Notice how the initializing array gets deconstructed, but an array added added later stays in the form of an array: let myAnimals = new Set(['🐷', '🐢', '🐷', '🐷']); myAnimals.add(['🐨', '🐑']); myAnimals.add({ name: 'Rud', type: '🐢' }); console.log(myAnimals.size); // 4 myAnimals.forEach(animal => { console.log(animal); }); // 🐷 // 🐢 // ["🐨", "🐑"] // Object { name: "Rud", type: "🐢" } Strings are a valid iterable so they can also be passed-in to initialize a set: console.log('Only unique characters will be in this set.'.length); // 43 let sentence = new Set('Only unique characters will be in this set.'); console.log(sentence.size); // 18 On top of using forEach on a set, for…of loops can also be used to iterate over sets: let moreAnimals = new Set(['🐺', '🐴', '🐕', '🐇']); for (let animal of moreAnimals) { console.log(`Howdy ${ animal }`); } // Howdy 🐺 // Howdy 🐴 // Howdy 🐕 // Howdy 🐇

    Keys and Values

    Sets also have the keys and values methods, with keys being an alias for values, so both methods do exactly the same thing. Using either of these methods returns a new iterator object with the values of the set in the same order in which they were added to the set. Here’s an example: let partyItems = new Set(['🍕', '🍾', '🎊']); let items = partyItems.values(); console.log(items.next()); console.log(items.next()); console.log(items.next()); console.log(items.next().done); // Object { // done: false, // value: "🍕" // } // Object { // done: false, // value: "🍾" // } // Object { // done: false, // value: "🎊" // } // true

    Console Features

    JavaScript Console Features console features How long does it take to perform a for-loop 100.000 times: console.time(); for (i = 0; i < 100000; i++) { // some code } console.timeEnd();

    HTML DOM console.table() Method

    Write a table in the console: console.table(["Audi", "Volvo", "Ford"]);

    adjustFontSize

    <a href="javascript:adjustFontSize('14px');">仲細D都得</a> function adjustFontSize(size){// console.log('adjustFontSize');$(".set-font-aera").css({"font-size":size});window.localStorage["fontSize"] = size; }

    FlappyBird

    FlappyBird

    跨浏览器添加事件 经典实例

    //跨浏览器添加事件 function addEvent(obj,type,fn){ if(obj.addEventListener){ obj.addEventListener(type,fn,false); }else if(obj.attachEvent){//IE obj.attchEvent('on'+type,fn); } }

    跨浏览器移除事件 经典实例

    //跨浏览器移除事件 function removeEvent(obj,type,fn){ if(obj.removeEventListener){ obj.removeEventListener(type,fn,false); }else if(obj.detachEvent){//兼容IE obj.detachEvent('on'+type,fn); } }

    跨浏览器阻止默认行为 经典实例

    //跨浏览器阻止默认行为 function preDef(ev){ var e = ev || window.event; if(e.preventDefault){ e.preventDefault(); }else{ e.returnValue =false; } }

    跨浏览器获取目标对象 经典实例

    //跨浏览器获取目标对象 function getTarget(ev){ if(ev.target){//w3c return ev.target; }else if(window.event.srcElement){//IE return window.event.srcElement; } }

    跨浏览器获取滚动条位置 经典实例

    //跨浏览器获取滚动条位置,sp == scroll position function getSP(){ return{ top: document.documentElement.scrollTop || document.body.scrollTop, left : document.documentElement.scrollLeft || document.body.scrollLeft; } }

    跨浏览器获取可视窗口大小 经典实例

    //跨浏览器获取可视窗口大小 function getWindow () { if(typeof window.innerWidth !='undefined') { return{ width : window.innerWidth, height : window.innerHeight } } else{ return { width : document.documentElement.clientWidth, height : document.documentElement.clientHeight } } },

    js 对象冒充 经典实例

    <script type = 'text/javascript'> function Person(name , age){ this.name = name ; this.age = age ; this.say = function(){ return "name : "+ this.name + " age: "+this.age ; } ; } var o = new Object() ;//可以简化为Object() Person.call(o , "zhangsan" , 20) ; console.log(o.say() );//name : zhangsan age: 20 </script>

    js 异步加载和同步加载 经典实例

    异步加载也叫非阻塞模式加载,浏览器在下载js的同时,同时还会执行后续的页面处理。 在script标签内,用js创建一个script元素并插入到document中,这种就是异步加载js文件了: (function() { var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true; s.src = 'http://yourdomain.com/script.js'; var x = document.getElementsByTagName('script')[0]; x.parentNode.insertBefore(s, x); })();

    同步加载 经典实例

    平常默认用的都是同步加载。 如: <script src="http://yourdomain.com/script.js"></script> 同步模式又称阻塞模式,会阻止浏览器的后续处理。 停止了后续的文件的解析,执行,如图像的渲染。 浏览器之所以会采用同步模式,是因为加载的js文件中有对dom的操作,重定向,输出document等默认行为,所以同步才是最安全的。 通常会把要加载的js放到body结束标签之前,使得js可在页面最后加载,尽量减少阻塞页面的渲染。 这样可以先让页面显示出来。 同步加载流程是瀑布模型,异步加载流程是并发模型。

    js获取屏幕坐标 经典实例

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"/> <meta name="auther" content="fq" /> <title>获取鼠标坐标</title> </head> <body> <script type="text/javascript"> function mousePosition(ev){ if(ev.pageX || ev.pageY){ return {x:ev.pageX, y:ev.pageY}; } return { x:ev.clientX + document.body.scrollLeft - document.body.clientLeft, y:ev.clientY + document.body.scrollTop - document.body.clientTop }; } function mouseMove(ev){ ev = ev || window.event; var mousePos = mousePosition(ev); document.getElementById('xxx').value = mousePos.x; document.getElementById('yyy').value = mousePos.y; } document.onmousemove = mouseMove; </script> X:<input id="xxx" type="text" /> Y:<input id="yyy" type="text" /> </body> </html> 注释: 1.documentElement 属性可返回文档的根节点。 2.scrollTop() 为滚动条向下移动的距离 3.document.documentElement.scrollTop 指的是滚动条的垂直坐标 4.document.documentElement.clientHeight 指的是浏览器可见区域高度 DTD已声明的情况下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 如果在页面中添加这行标记的话

    IE 经典实例

    document.body.clientWidth ==> BODY对象宽度 document.body.clientHeight ==> BODY对象高度 document.documentElement.clientWidth ==> 可见区域宽度 document.documentElement.clientHeight ==> 可见区域高度

    Firefox 经典实例

    document.documentElement.scrollHeight ==> 浏览器所有内容高度 document.body.scrollHeight ==> 浏览器所有内容高度 document.documentElement.scrollTop ==> 浏览器滚动部分高度 document.body.scrollTop ==>始终为0 document.documentElement.clientHeight ==>浏览器可视部分高度 document.body.clientHeight ==> 浏览器所有内容高度

    Chrome 经典实例

    document.documentElement.scrollHeight ==> 浏览器所有内容高度 document.body.scrollHeight ==> 浏览器所有内容高度 document.documentElement.scrollTop==> 始终为0 document.body.scrollTop==>浏览器滚动部分高度 document.documentElement.clientHeight ==> 浏览器可视部分高度 document.body.clientHeight ==> 浏览器所有内容高度 浏览器所有内容高度即浏览器整个框架的高度,包括滚动条卷去部分+可视部分+底部隐藏部分的高度总和浏览器滚动部分高度即滚动条卷去部分高度即可视顶端距离整个对象顶端的高度。 综上1、document.documentElement.scrollTopdocument.body.scrollTop始终有一个为0,所以可以用这两个的和来求scrollTop2、scrollHeight、clientHeightDTD已声明的情况下用documentElement,未声明的情况下用bodyclientHeight 在IE和FF下,该属性没什么差别,都是指浏览器的可视区域,即除去浏览器的那些工具栏状态栏剩下的页面展示空间的高度。

    PageX和clientX 经典实例

    PageX:鼠标在页面上的位置,从页面左上角开始,即是以页面为参考点,不随滑动条移动而变化clientX:鼠标在页面上可视区域的位置,从浏览器可视区域左上角开始,即是以浏览器滑动条此刻的滑动到的位置为参考点,随滑动条移动 而变化.可是悲剧的是,PageX只有FF特有,IE则没有这个,所以在IE下使用这个: PageY=clientY+scrollTop-clientTop;(只讨论Y轴,X轴同理,下同)scrollTop代表的是被浏览器滑动条滚过的长度offsetX:IE特有,鼠标相比较于触发事件的元素的位置,以元素盒子模型的内容区域的左上角为参考点,如果有boder`,可能出现负值只有clientXscreenX 皆大欢喜是W3C标准.其他的,都纠结了. 最给力的是,chromesafari一条龙通杀!完全支持所有属性

    js拖拽效果 经典实例

    <!doctype html> <html lang="zn-CN"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> <title></title> <style type="text/css"> #login{ height: 100px; width: 100px; border: 1px solid black; position: relative; top:200px; left: 200px; background: red; } </style> </head> <body> <div id="login"></div> <script type="text/javascript"> var oDiv = document.getElementById("login"); oDiv.onmousedown = function(e){ var e = e || window.event;//window.event兼容IE,当事件发生时有效 var diffX = e.clientX - oDiv.offsetLeft;//获取鼠标点击的位置到所选对象的边框的水平距离 var diffY = e.clientY - oDiv.offsetTop; document.onmousemove = function(e){ //需设为document对象才能作用于整个文档 var e = e||window.event; oDiv.style.left = e.clientX - diffX + 'px';//style.left表示所选对象的边框到浏览器左侧距离 oDiv.style.top = e.clientY -diffY + 'px'; }; document.onmouseup = function(){ document.onmousemove = null;//清除鼠标释放时的对象移动方法 document.onmouseup = null; } } </script> </body> </html>
    offsetTop 返回的是数字,而 style.top 返回的是字符串,除了数字外还带有单位: px

    js获取图片原始大小尺寸 经典实例

    var img = $("#img_id"); // Get my img elem var pic_real_width, pic_real_height; $("&lt;img/&gt;") // Make in memory copy of image to avoid css issues .attr("src", $(img).attr("src")) .load(function() { pic_real_width = this.width; // Note: $(this).width() will not pic_real_height = this.height; // work for in memory images. });

    js循环遍历数 经典实例

    <script> //循环遍历数组 var animals = ["cat",'dog','human','whale','seal']; var animalString = ""; for(var i = 0;i<animals.length;i++){ animalString += animals[i] + " "; } alert(animalString); //输出数组里的每个项 </script>

    遍历二维数组 经典实例

    <script> var arr=[[0,0,0,0,0,0],[0,0,1,0,0,0],[0,2,0,3,0,0],[0,0,0,0,0,0]]; for(var i=0;i<arr.length;i++){ //遍历每一个具体的值 for(var j=0;j<arr[i].length;j++){ document.writeln(arr[i][j]+" "); } document.writeln("<br/>"); } </script>

    阻止表单重复提交 经典实例

    有两种方法可以解决: 一是提交之后,立刻禁用点击按钮; 第二种就是提交之后取消后续的表单提交操作。 document.getElementById("btn").disabled = true;//第一次提交后,将按钮禁用 这种方式只能用于通过提交按钮防止重复提交,还可以使用如下方式: var flag = false;//设置一个监听变量 if(flag ==true)return;//退出事件 flag = true;//表示提交过一次了

    字符串部分 经典实例

    在字符串中查找子字符串 经典实例

    <script type="text/javascript"> var test = 'Welcome to my blog!'; var value = 'blog'; var subValue = test.indexOf(value); console.log(subValue);//14,子字符串的索引 </script>

    Number和Math部分 经典实例

    数字可以是一个直接量,也可以是一个对象,但是Math对象不同,他没有构造函数,并且其所有的属性和方法都是直接通过这个对象来访问的

    把十进制转化为一个十六进制值 经典实例

    var num = 255; console.log(num.toString(16));// js中,十进制数字以0x开头,八进制数字总是以0开头

    随进产生颜色 经典实例

    <script type="text/javascript"> function randomVal(val){ return Math.floor(Math.random()*(val + 1)); } function randomColor(){ return 'rgb(' + randomVal(255) + ',' + randomVal(255) + ',' + randomVal(255) + ')'; } </script> 目前,所有浏览器都支持RGB表示法和十六进制表示法,除了IE7,它只支持十六进制表示法

    在角度和弧度之间转换 经典实例

    var rad = degrees*(Math.PI/180); var degrees = rad*(180/Math.PI);

    数组部分 经典实例

    创建多维数组 经典实例

    <script type="text/javascript"> var arrayLength = 3;//设置数组长度 //创建数组 var multiArray = new Array(arrayLength); for(var i =0;i<multiArray.length;i++){ multiArray[i] = new Array(arrayLength); } //给第一个数组索引添加项 multiArray[0][0] = 'phone'; multiArray[0][1] = 'book'; multiArray[0][2] = 'TV'; //第二个 multiArray[1][0] = 2; multiArray[1][1] = 1; multiArray[1][2] = 98; //第三个 multiArray[2][0] = ['java','python']; multiArray[2][1] = ['js','C++']; multiArray[2][2] = ['Haskell','php']; </script>

    排序数组 经典实例

    <script type="text/javascript"> var fruits = ['banana','apple','orange','strawberry']; console.log(fruits.sort());//Array [ "apple", "banana", "orange", "strawberry" ] var num = [32,43,2,5,-23,0,4]; console.log(num.sort());//Array [ -23, 0, 2, 32, 4, 43, 5 ] </script> Array对象的sort方法会按照字母顺序来排序数组元素。 对于数字,是按照字符编码的顺序进行排序function compare(a,b){ return a-b; } var num = [32,43,2,5,-23,0,4]; console.log(num.sort(compare));//Array [ -23, 0, 2, 4, 5, 32, 43 ]

    Date日期时间部分 经典实例

    js计算时间差 经典实例

    var date1=new Date(); //开始时间,当前时间 var date2=new Date(); //结束时间,需传入时间参数 var date3=date2.getTime()-date1.getTime(); //时间差的毫秒数 //计算出相差天数 var days=Math.floor(date3/(24*3600*1000)); //计算出小时数 var leave1=date3%(24*3600*1000); //计算天数后剩余的毫秒数 var hours=Math.floor(leave1/(3600*1000)); //计算相差分钟数 var leave2=leave1%(3600*1000); //计算小时数后剩余的毫秒数 var minutes=Math.floor(leave2/(60*1000)); //计算相差秒数 var leave3=leave2%(60*1000); //计算分钟数后剩余的毫秒数 var seconds=Math.round(leave3/1000); console.log(" 相差 "+days+"天 "+hours+"小时 "+minutes+" 分钟"+seconds+" 秒");

    正则部分 经典实例

    js实现千分位分隔 经典实例

    <script type="text/javascript"> function cc(s){ if(/[^0-9\.]/.test(s)) return "invalid value"; s=s.replace(/^(\d*)$/,"$1."); s=(s+"00").replace(/(\d*\.\d\d)\d*/,"$1"); s=s.replace(".",","); var re=/(\d)(\d{3},)/; while(re.test(s)) s=s.replace(re,"$1,$2"); s=s.replace(/,(\d\d)$/,".$1"); return "¥" + s.replace(/^\./,"0.") } </script> <input onchange="this.value=cc(this.value)" />

    js判断传入参数是否为质数 经典实例

    function fn(input) { input = parseInt(input,10); return isPrime(input) ? 'is prime' : 'not prime'; } function isPrime(input) { if (input < 2) { return false; } else { for (var i = 2; i <= Math.sqrt(input); i++) { if (input % i == 0) { return false; } } } return true; }

    js判断字符串出现最多的字符,并统计次数 经典实例

    //js实现一个函数,来判断一个字符串出现次数最多的字符,并统计这个次数 function countStr(str){ var obj = {}; for(var i = 0, l = str.length,k; i < l ;i++){ k = str.charAt(i); if(obj[k]){ obj[k]++; }else{ obj[k] = 1; } } var m = 0,i=null; for(var k in obj){ if(obj[k] > m){ m = obj[k]; i = k; } } return i + ':' + m; }

    requestAnimationFrame() method for smooth animations

    requestAnimationFrame() method was introduced to help us execute animation Why we need another hero- requestAnimationFrame First of all, lets talk about requestAnimationFrame() as an idea and why we even need such a method. Traditionally to create an animation in JavaScript, we relied on setTimeout() called recursively or setInterval() to repeatedly execute some code to make changes to an element frame by frame, such as once every 50 milliseconds: var adiv = document.getElementById('mydiv') var leftpos = 0 setInterval(function(){ leftpos += 5 adiv.style.left = leftpos + 'px' // move div by 5 pixels each time }, 50) // run code every 50 milliseconds While the above code is logically sound, its actual execution is far from perfect. The problem with using setTmeout/setInterval for executing code that changes something on the screen is twofold. What we specify as the delay (ie: 50 milliseconds) inside these functions are often times not honoured due to changes in user system resources at the time, leading to inconsistent delay intervals between animation frames. Even worse, using setTimeout() or setInterval() to continuously make changes to the user's screen often induces "layout thrashing", the browser version of cardiac arrest where it is forced to perform unnecessary reflows of the page before the user's screen is physically able to display the changes. This is bad -very bad- due to the taxing nature of page reflows, especially on mobile devices where the problem is most apparent, with janky page loads and battery drains. requestAnimationFrame() to the rescue It is for the above reasons requestAnimationFrame() was introduced. The method in a nutshell allows you to execute code on the next available screen repaint, taking the guess work out of getting in sync with the user's browser and hardware readiness to make changes to the screen. When we call requestAnimationFrame() repeatedly to create an animation, we are assured that our animation code is called when the user's computer is actually ready to make changes to the screen each time, resulting in a smoother, more efficient animation. Furthermore, code called via requestAnimationFrame() and running inside background tabs in your browser are either paused or slowed down significantly (to 2 frames per second or less) automatically to further save user system resources- there's no point in running an animation that isn't being seen is there? So requestAnimationFrame() should be used in place of setTimeout/ setInterval for animations, but how exactly do we go about doing that? Before we get to that, lets look at browser support first. requestAnimationFrame() today enjoys wide adoption amongst modern browsers- IE10+, FF11+, Chrome, and Safari etc. For some older versions of these browsers, a vendor prefix is needed in front of the method name to work. Even on browsers that don't support this method in any incarnation, we can simply fallback in those cases to setTimeout() instead to call the code after a certain delay instead. The following code creates a universal rrequestAnimationFrame() and its counterpart cancelAnimationFrame() function that works in the maximum number of browsers, with a fallback built in: window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(f){return setTimeout(f, 1000/60)} // simulate calling code 60 window.cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame || function(requestID){clearTimeout(requestID)} //fall back For the fallback setTimeout() code, notice the delay being set at 1000/60, or around 16.7 milliseconds. This value simulates how often the real requestAnimationFrame() will typically be called by the browser each time it's invoked based on the typical user's screen refresh rate of 60 frames per second. Understanding and using requestAnimationFrame() The syntax for requestAnimationFrame is very straightforward: requestAnimationFrame(callback) We enter a callback function containing the code we wish to run, and requestAnimationFrame() will run it when the screen is ready to accept the next screen repaint. Some noteworthy details: The callback function is automatically passed a timestamp indicating the precise time requestAnimationFrame() was called. requestAnimationFrame() returns a non 0 integer that can be passed into its nemesis counterpart cancelAnimationFrame() to cancel a requestAnimationFrame() call Here's an example of calling requestAnimationFrame() once to move a DIV just 5 pixels from its original location on the screen: var adiv = document.getElementById('mydiv') var leftpos = 0 requestAnimationFrame(function(timestamp){ leftpos += 5 adiv.style.left = leftpos + 'px' }) The above code is very similar to using setTimeout() to run the same code, except instead of after the user defined delay, the code is called on the next available screen repaint, typically around 16.7 milliseconds based on a typical screen refresh rate of 60fps. The exact number may fluctuate and frankly doesn't matter; what's important to realize is that the browser will now intelligently invoke our code only when it is ready to accept changes to the screen, not before. Calling requestAnimationFrame() once is pretty meaningless most of the time. The magic happens when we call it "recursively" to construct the desired animation frame by frame, with each frame being called only when the browser is ready for it. This this how requestAnimationFrame() becomes superior to setTimeout or setInterval when it comes to handling animation related code efficiently. Lets rewrite our initial example of moving a DIV across the screen 5 pixels at a time using requestAnimationFrame(): var adiv = document.getElementById('mydiv') var leftpos = 0 function movediv(timestamp){ leftpos += 5 adiv.style.left = leftpos + 'px' requestAnimationFrame(movediv) // call requestAnimationFrame again to animate next frame } requestAnimationFrame(movediv) // call requestAnimationFrame and pass into it animation function The above code shows the basic blueprint for using requestAnimationFrame() to create an animation, by defining your animation code inside a function, then inside this function calling itself recursively through requestAnimationFrame() to produce each frame of our animation. To kick start the animation, we make a call to requestAnimationFrame() outside the animation function with that function as the parameter. Animation over time in requestAnimationFrame() So it's simple enough to repeatedly call an animation function using requestAnimationFrame(), but most animations are much more finicky, having to stop at some point after a certain objective has been achieved over a certain amount of time. Take our example of moving the DIV above; in a real life scenario, what we probably want to do is move the DIV 400 pixels to the right over a time of say 2 seconds. To do this with requestAnimationFrame(), we can take advantage of the timestamp parameter that's passed into the callback function. Lets see how this works now, by retooling our DIV moving code above so it moves the DIV a certain distance over a certain amount of time: var adiv = document.getElementById('mydiv') var starttime function moveit(timestamp, el, dist, duration){ //if browser doesn't support requestAnimationFrame, generate our own timestamp using Date: var timestamp = timestamp || new Date().getTime() var runtime = timestamp - starttime var progress = runtime / duration progress = Math.min(progress, 1) el.style.left = (dist * progress).toFixed(2) + 'px' if (runtime < duration){ // if duration not met yet requestAnimationFrame(function(timestamp){ // call requestAnimationFrame again with parameters moveit(timestamp, el, dist, duration) }) } } requestAnimationFrame(function(timestamp){ starttime = timestamp || new Date().getTime() //if browser doesn't support requestAnimationFrame, generate our own timestamp using Date moveit(timestamp, adiv, 400, 2000) // 400px over 1 second }) Demo: Move DIV 400px in 2 seconds Lets go over how this works now. Just before the animation runs, we set the startime variable to the current time using either requestAnimationFrame's timestamp parameter, or if requestAnimationFrame isn't supported, a less precise new Date().getTime() instead. The former is a value automatically passed in as the first parameter of the callback function of requestAnimationFrame that contains a highly accurate representation of the current time in milliseconds (accurate to 5 microseconds). This lets us know when the animation started running. Inside the animation function moveit(), we capture the current time of the current "frame" using variable timestamp. We use the difference between that and the animation starttime to figure out at what "point" along the animation we're currently at, and change the DIV's position accordingly out of the total distance (ie: 400px). Slowing down or cancelling requestAnimationFrame() The standard requestAnimationFrame runs at around 60fps under ideal conditions (or once every 16.7ms), in sync with the refresh rate of the typical monitor. If your animation requires a different frames per second (up to 60 fps) or simply doesn't require that high a level of refresh rate, you can slow it down by calling requestAnimationFrame inside setTimeout(). That way, you get the desired frame rate while reaping the benefits of requestAnimationFrame: var adiv = document.getElementById('mydiv') var leftpos = 0 var fps = 20 function movediv(timestamp){ setTimeout(function(){ //throttle requestAnimationFrame to 20fps leftpos += 5 adiv.style.left = leftpos + 'px' requestAnimationFrame(movediv) }, 1000/fps) } requestAnimationFrame(movediv) In this version of moving a DIV horizontally, we're throttling the frames per second to roughly 20, by calling requestAnimationFrame inside setTimeout() each time. - Cancelling requestAnimationFrame() Just like with setTimeout/ setInterval, you can cancel a requestAnimationFrame call, and in identical fashion as well. requestAnimationFrame when called returns a non 0 integer that can be captured inside a variable and passed into its nemesis counterpart cancelAnimationFrame() to stop it from being invoked again. The following logs the timestamp parameter value of requestAnimationFrame for two seconds, using cancelAnimationFrame to stop the former: var reqanimationreference function logtimestamp(timestamp){ console.log(timestamp) reqanimationreference = requestAnimationFrame(logtimestamp) } requestAnimationFrame(logtimestamp) setTimeout(function(){ // cancel requestAnimationFrame after 2 seconds cancelAnimationFrame(reqanimationreference) }, 2000) Here is a slightly more elaborate example that continuously changes a DIV's width using requestAnimationFrame when the mouse enters the parent container (onmouseenter), and cancels it onmouseleave: Demo: Move mouse over battery View Source Code Conclusion As you can see, requestAnimationFrame() is actually very simple in concept and execution, once you understand its purpose and common patterns. A lot of frameworks such as jQuery 3.0 utilize requestAnimationFrame() internally for all animation related functions, though it's definitely better to understand how this method works natively so you can take advantage of it in any JavaScript environment.

    Tutorials

    Smooth Scrolling HTML Bookmarks using JavaScript (natively or jQuery) See how to use native JavaScript to create smooth scrolling HTML bookmark links inside the page, and for those that need legacy browser support, using jQuery instead. This promises to be one smooth tutorial! Web Animation API- Unleashing the Power of CSS keyframes in JavaScript Animate elements in JavaScript using the power of CSS keyframes animationz with the Web Animation API! In this tutorial, I'll introduce you to WAAPI, browser support and polyfill, and how to start using this awesome API today. Top five features in JavaScript ES6 Worth Mastering JavaScript ES6 adds a slew of new features to the JavaScript language, some more groundbreaking and widely applicable than others. In this article I list the top 5 JavaScript ES6 features I find most indispensible. Understanding let and const in JavaScript ES6 Get to know all about "let" and "const" in JavaScript ES6, and how it differs from the age old "var" keyword in defining variables. Displaying Content in Full Screen using the Fullscreen API in JavaScript Open up any content on your page in full screen mode with just a few lines of JavaScript using the Full Screen API. Introduction to JavaScript Async Functions- Promises simplified See how to use JavaScript async functions with JavaScript Promises to further simplify asynchronous operations in JavaScript, and produce code that's easier to read and debug to boot. Four Essential JavaScript functions to tame CSS3 Transitions and Animations See four JavaScript functions that help you unlock the full potential of CSS Transitions and Animations, by pausing them, detecting when they've finished playing, and more. Understanding JavaScript's requestAnimationFrame() method for smooth animations requestAnimationFrame() is a JavaScript method for creating smoother, less resource intensive JavaScript animations. See how to take advantage of this method in this comprehensive tutorial. Determining how much the user has scrolled the page using JavaScript or jQuery Learn how to detect the amount the user has scrolled the page using JavaScript or jQuery, in either pixels travelled or as a percentage of the whole page. Reading and copying selected text to clipboard using JavaScript In this tutorial, we'll see how to read the textual contents of a user selection, dynamically select some text on the page, and last but not least, copy whatever is selected to clipboard, all using just JavaScript. Not a trace of Flash here! Beginner's Guide to JavaScript Promises JavaScript Promises are a new addition to ECMAscript 6 that aims to provide a cleaner, more intuitive way to deal with the completion (or failure) of asynchronous tasks. In this tutorial we'll deliver the promise of JavaScript Promises to the uninitiated! Overview of JavaScript Arrow Functions One of the exciting new additions to ECMAscript 6 is Arrow Functions, a compact way to define anonymous functions that also simplifies the handling of the "this" object inside it. In this tutorial we'll go over all you need to know about the new function syntax before it supplants anonymous functions everywhere. Matching multiple CSS media queries using window.matchMedia() A common question that gets asked is how to use JavaScript's window.matchMedia() method to react to multiple CSS media queries. In this tutorial we explore how. Converting objects to arrays using Array.prototype.slice.call() We break down Array.prototype.slice.call() to see how it works to convert array-like objects into true arrays in this quick tutorial. Introduction to Touch events in JavaScript In this tutorial lets get touchy feely with JavaScript, but examining its touch related events and how they are used to detect and respond to touch and swipe events. Preloading images and executing code only after all images have loaded See how to refine the process of preloading images to detect when all images have actually been preloaded and react accordingly. Setting CSS3 properties using JavaScript With the numerous CSS vendor prefixes one has to contend with when it comes to defining CSS3 properties such as -moz-box-shadow or -webkit-border-radius, setting them in JavaScript can be even more confusing. This tutorial looks at how to how to streamline the setting of CSS3 property values in JavaScript, by checking for and targeting only the version of a CSS3 property the browser supports. Going beyond cookies- Using DOM sessionStorage and localStorage to persist larger amounts of info HTML5 introduces DOM Storage, a new way of storing data on the client side that overcomes the disk space limitations of JavaScript cookies. This tutorial looks at how to take advantage of DOM Storage in browsers today. Using document.createElement() to test for browser support for an element Most of us are familiar with using object detection or the Navigator object to check for backing for a given JavaScript object or method, but these techniques do not work well when the objective is to check whether the browser supports a particular HTML element, such as the <canvas> element. This is where document.createElement() can be very helpful. The onmousewheel event of JavaScript The onmousewheel event fires whenever the user moves the mouse wheel either upwards or downwards, and can provide yet another way for users to interact with your JavaScript. In this tutorial, lets see how to take advantage of onmousewheel across browsers. Handling runtime errors in JavaScript using try/catch/finally The try/catch/finally statement of JavaScript lets you dip your toes into error prune territory and "reroute" when a runtime error has occurred. Learn all about this often misunderstood statement in this tutorial. Dynamically loading an external JavaScript or CSS file External JavaScript or CSS files do not always have to be synchronously loaded as part of the page, but dynamically as well. In this tutorial, we'll see how to load, remove, and replace external JavaScript and CSS files on demand and asynchronously. It the era of Ajax, it's a handy thing to know. JavaScript and memory leaks If you're not careful, your JavaScript code may leak memory and sometimes even bring the visitor's browser to its knees. This tutorial looks at different leak patterns in JavaScript and how to fix them. JavaScript Closures 101- they're not magic Morris Johns explains JavaScript closures, a powerful yet often bewildering concept, in a gentle, step by step fashion. Conditional Compilation of JScript/ JavaScript in IE IE supports a little known feature called conditional compilation that selectively compiles any block of JScript or JavaScript depending on your script logic. Think of it as the absolute form of object detection. External JavaScript and PHP External JavaScript can reference not just .js files, but PHP scripts as well. See how this is done, and the wonderful possibilities linking PHP to JavaScript bring. Changing Select element content on the fly This tutorial explains how to change a select element's content using JavaScript, from adding new options to modifying and deleting them. It also shows how to create a 2 level interdependent select list. Determining cookie support in client's browser If your script relies on JavaScript cookies to store and persist information, it's a good idea to always first make sure the user's browser has cookies enabled. This tutorial shows you how to perform this detection. Introductory Guide to Regular Expressions Always wanted to learn about Regular Expressions in JavaScript? With this comprehensive yet gentle tutorial on the subject, you'll be on your way to slashing and validating string input using Regular Expressions in no time!

    Introductory Tutorials

    JavaScript Primer Creating alert, confirm, and prompt boxes Understanding "event handlers" in JavaScript One event handler, many actions Adding more than one JavaScript to a page The Type and Language attributes of JavaScript How I learned JavaScript

    Forms and form validation

    Accessing and validating forms Manipulating radio and check boxes Enabling/ disabling form elements Accessing the select element of a form Creating combo link menus Changing select element content on the fly

    External JavaScript

    Creating external JavaScript libraries External Javascript and PHP Dynamically loading an external JavaScript or CSS file Restricting access of JavaScript libraries to designated domains

    cookies

    Session-only cookies Determining cookie support in client's browser

    Math & Random scripts

    The Math object Number rounding in JavaScript Formatting numbers for decimals and significant digits Generating a random number in JavaScript Generating weighed random numbers Using JavaScript to create random scripts Randomizing the display order of content using JS

    Variables and functions

    Determining the existence of a variable Robust functions via the arguments array Using named arguments in JavaScript functions Variable and expression shortcuts The switch statement of JavaScript Adding properties to a literal in JavaScript Avoiding variable and function conflicts in JavaScript Flag Variables, Validation, & Function Control Tackling JavaScript strict warnings

    Regular Expressions

    Introductory Guide to Regular Expressions Programmer's Guide to Regular Expressions

    with content

    Using JavaScript to statically display elements JavaScript and Dynamic Content Creating an attractive Hover Menu using CSS & JavaScript

    Date & Time

    Date, time, and creating a live clock in JavaScript Calculating the difference between two dates

    Interacting with images

    Accessing images & creating image rollovers Preloading images and executing code only after all images have loaded Creating depressible images Building a JavaScript image slideshow

    Windows and frames

    Windows and JavaScript Determining whether a browser window is open Moving, scrolling, and resizing browser window Loading two frames with one link... Opening windows in theatre and channel mode (IE) Creating window remote controls Detecting user's screen size and resolution

    Strings (text)

    Strings in JavaScript Part 1 Strings in JavaScript Part II

    Objects and entities

    JavaScript and OOP Creating custom objects in JavaScript The prototype object of JavaScript Sending objects from one page to another

    Browser and features detection

    Using the navigator object to detect browser Using object detection to detect browser type Using document.createElement() to test for browser support for an element

    Error handling

    The onerror event of the window object Handling runtime errors in JavaScript using try/catch/finally

    Keyboard and printer interaction

    Scripting the keyboard in JavaScript onbeforeprint and onafterprint events of IE Using window.print() to print a document

    Tabular Data Control (IE only)

    Introduction to Tabular Data Control Sorting a Tabular Data Control Filtering a Tabular Data Control

    Other tutorials

    Performance tips for JavaScript Creating custom collections in the DOM (via ID attribute) Creating customizable alert boxes using VBScript

    Animating the Canvas

    Animating the Canvas

    appendChild

    Uncaught TypeError: Cannot read property 'appendChild' of null but you have a class name or id in the HTML... If your script tag is in the head, the JavaScript is loaded before your HTML. You will need to add defer to your script like so: <script src="script.js" defer></script> or put the script at bottom of page

    Declaring global variable within function

    To declare JavaScript global variables inside function, you need to use window object. For example: window.value=90; Now it can be declared inside any function and can be accessed from any function. For example: function m(){ window.value=100;//declaring global variable by window object } function n(){ alert(window.value);//accessing global variable from other function }

    Internals of global variable in JavaScript

    When you declare a variable outside the function, it is added in the window object internally. You can access it through window object also. For example: var value=50; function a(){ alert(window.value);//accessing global variable }

    What is a Callback?

    Simply put: A callback is a function that is to be executed after another function has finished executing — hence the name ‘call back’. More complexly put: In JavaScript, functions are objects. Because of this, functions can take functions as arguments, and can be returned by other functions. Functions that do this are called higher-order functions. Any function that is passed as an argument is called a callback function. Why do we need Callbacks? For one very important reason — JavaScript is an event driven language. This means that instead of waiting for a response before moving on, JavaScript will keep executing while listening for other events. Lets look at a basic example: function first(){ console.log(1); } function second(){ console.log(2); } first(); second(); As you would expect, the function first is executed first, and the function second is executed second — logging the following to the console: // 1 // 2 All good so far. But what if function first contains some sort of code that can’t be executed immediately? For example, an API request where we have to send the request then wait for a response? To simulate this action, were going to use setTimeout which is a JavaScript function that calls a function after a set amount of time. We’ll delay our function for 500 milliseconds to simulate an API request. Our new code will look like this: function first(){ // Simulate a code delay setTimeout( function(){ console.log(1); }, 500 ); } function second(){ console.log(2); } first(); second(); It’s not important that you understand how setTimeout() works right now. All that matters is that you see we’ve moved our console.log(1); inside of our 500 millisecond delay. So what happens now when we invoke our functions? first(); second(); // 2 // 1 Even though we invoked the first() function first, we logged out the result of that function after the second() function. It’s not that JavaScript didn’t execute our functions in the order we wanted it to, it’s instead that JavaScript didn’t wait for a response from first() before moving on to execute second(). So why show you this? Because you can’t just call one function after another and hope they execute in the right order. Callbacks are a way to make sure certain code doesn’t execute until other code has already finished execution. Create a Callback First, open up your Chrome Developer Console and type the following function declaration into your console: function doHomework(subject) { alert(`Starting my ${subject} homework.`); } Above, we’ve created the function doHomework . Our function takes one variable, the subject that we are working on. Call your function by typing the following into your console: doHomework('math'); // Alerts: Starting my math homework. Now lets add in our callback — as our last parameter in the doHomework() function we can pass in callback. The callback function is then defined in the second argument of our call to doHomework(). function doHomework(subject, callback) { // here callback is variable alert(`Starting my ${subject} homework.`); callback(); // this call is not fixed, depend on the true calling command } doHomework('math', function() { alert('Finished my homework'); }); As you’ll see, if you type the above code into your console you will get two alerts back to back: Your ‘starting homework’ alert, followed by your ‘finished homework’ alert. But callback functions don’t always have to be defined in our function call. They can be defined elsewhere in our code like this: function doHomework(subject, callback) { alert(`Starting my ${subject} homework.`); callback(); } function alertFinished(){ alert('Finished my homework'); } doHomework('math', alertFinished); This result of this example is exactly the same as the previous example, but the setup is a little different. As you can see, we’ve passed the alertFinished function definition as an argument during our doHomework() function call! A real world example Last week I published an article on how to Create a Twitter Bot in 38 lines of code. The only reason the code in that article works is because of Twitters API. When you make requests to an API, you have to wait for the response before you can act on that response. This is a wonderful example of a real-world callback. Here’s what the request looks like: T.get('search/tweets', params, function(err, data, response) { if(!err){ // This is where the magic will happen } else { console.log(err); } }) T.get simply means we are making a get request to Twitter There are three parameters in this request: ‘search/tweets’, which is the route of our request, params which are our search parameters, and then an anonymous function which is our callback. A callback is important here because we need to wait for a response from the server before we can move forward in our code. We don’t know if our API request is going to be successful or not so after sending our parameters to search/tweets via a get request, we wait. Once Twitter responds, our callback function is invoked. Twitter will either send an err (error) object or a response object back to us. In our callback function we can use an if() statement to determine if our request was successful or not, and then act upon the new data accordingly.

    Closures

    JavaScript variables can belong to the local or global scope. Global variables can be made local (private) with closures. In a web page, global variables belong to the window object. Global variables can be used (and changed) by all scripts in the page (and in the window). Global and local variables with the same name are different variables. Modifying one, does not modify the other. Variables created without a declaration keyword (var, let, or const) are always global, even if they are created inside a function. A Counter Dilemma Suppose you want to use a variable for counting something, and you want this counter to be available to all functions. You could use a global variable, and a function to increase the counter: Example // Initiate counter var counter = 0; // Function to increment counter function add() { counter += 1; } // Call add() 3 times add(); add(); add(); // The counter should now be 3 There is a problem with the solution above: Any code on the page can change the counter, without calling add(). The counter should be local to the add() function, to prevent other code from changing it: Example // Initiate counter var counter = 0; // Function to increment counter function add() { var counter = 0; counter += 1; } // Call add() 3 times add(); add(); add(); //The counter should now be 3. But it is 0 It did not work because we display the global counter instead of the local counter. We can remove the global counter and access the local counter by letting the function return it: Example // Function to increment counter function add() { var counter = 0; counter += 1; return counter; } // Call add() 3 times add(); add(); add(); //The counter should now be 3. But it is 1. It did not work because we reset the local counter every time we call the function. A JavaScript inner function can solve this. JavaScript Nested Functions All functions have access to the global scope. In fact, in JavaScript, all functions have access to the scope "above" them. JavaScript supports nested functions. Nested functions have access to the scope "above" them. In this example, the inner function plus() has access to the counter variable in the parent function: Example function add() { var counter = 0; function plus() {counter += 1;} plus(); return counter; } This could have solved the counter dilemma, if we could reach the plus() function from the outside. We also need to find a way to execute counter = 0 only once. We need a closure. JavaScript Closures Remember self-invoking functions? What does this function do? Example var add = (function() { var counter = 0; return function() {counter += 1; return counter} })(); add(); add(); add(); // the counter is now 3 Example Explained The variable add is assigned the return value of a self-invoking function. The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression. This way add becomes a function. The "wonderful" part is that it can access the counter in the parent scope. This is called a JavaScript closure. It makes it possible for a function to have "private" variables. The counter is protected by the scope of the anonymous function, and can only be changed using the add function. A closure is a function having access to the parent scope, even after the parent function has closed.

    Select selectedIndex Property

    Select a fruit and click the button: <select id="mySelect"> <option>Apple</option> <option>Orange</option> <option>Pineapple</option> <option>Banana</option> </select> <button type="button" onclick="myFunction()">Display index</button> function myFunction() { var x = document.getElementById("mySelect").selectedIndex; var y = document.getElementById("mySelect").options; alert("Index: " + y[x].index + " is " + y[x].text); }

    :contains selector

    Selecting multiple items from a list use the :contains selector to search for an element whose text includes certain text. $("#leftSelect option:contains(InfoCard Employee)").prop('selected', true);

    multiple select

    // arguments: reference to select list, callback function(optional) function getSelectedOptions(sel, fn) { var opts = [], opt; // loop through options in select list for (var i=0, len=sel.options.length; i<len; i++) { opt = sel.options[i]; // check if selected if ( opt.selected ) { // add to array of option elements to return from this function opts.push(opt); // invoke optional callback function if provided if (fn) { fn(opt); } } } // return array containing references to selected option elements return opts; } Our getSelectedOptions function includes a callback mechanism that enables handling each selected option as it is collected, so there is no need to loop through the set a second time. The callback function for this example is displayed here: // example callback function(selected options passed one by one) function callback(opt) { // display in textarea for this example var display = document.getElementById('display'); display.innerHTML += opt.value + ', '; // can access properties of opt, such as... //alert( opt.value ) //alert( opt.text ) //alert( opt.form ) } Onchange and Onsubmit Handling The example form above demonstrates obtaining the list of selected options both onchange and onsubmit. Onsubmit, we check the length of the list to report how many option elements have been selected. Onchange, we list the values of selected options in the textarea. The JavaScript below shows how onchange and onsubmit handling are set up for this example: // anonymous function onchange for select list with id demoSel document.getElementById('demoSel').onchange = function(e) { // get reference to display textarea var display = document.getElementById('display'); display.innerHTML = ''; // reset // callback fn handles selected options getSelectedOptions(this, callback); // remove ', ' at end of string var str = display.innerHTML.slice(0, -2); display.innerHTML = str; }; document.getElementById('demoForm').onsubmit = function(e) { // reference to select list using this keyword and form elements collection // no callback function used this time var opts = getSelectedOptions( this.elements['demoSel[]'] ); alert( 'The number of options selected is: ' + opts.length ); // number of selected options return false; // don't return online form }; Form Markup Markup for the example form above is displayed here: <form action="#" method="post" id="demoForm" class="demoForm"> <fieldset> <legend>Demo: Get Selected Options</legend> <p> <select name="demoSel[]" id="demoSel" size="4" multiple> <option value="scroll">Scrolling Divs JavaScript</option> <option value="tooltip">JavaScript Tooltips</option> <option value="con_scroll">Continuous Scroller</option> <option value="banner">Rotating Banner JavaScript</option> <option value="random_img">Random Image PHP</option> <option value="form_builder">PHP Form Generator</option> <option value="table_class">PHP Table Class</option> <option value="order_forms">PHP Order Forms</option> </select> <input type="submit" value="Submit" /> <textarea name="display" id="display" placeholder="view select list value(s) onchange" cols="20" rows="4" readonly></textarea> </p> </fieldset> </form> Name Attribute for Multiple Select Notice the name demoSel[] is applied to the example select box. Attach square brackets to the end of the name of a select-multiple type select box in order for server side code to treat selected options as an array. Otherwise only the last selected item will be provided. An ID can be used to obtain a reference to the select box in JavaScript as shown above.[1]

    some input checkbox functions

    use keypress <input type="checkbox" name="Colors" value="Bike" class="mycheckbox">My text<br> Jquery $('.mycheckbox').on('keypress', function(event) { if (event.which === 13) { $(this).prop('checked', !$(this).prop('checked')); } }); Another method is to use a type selector in order to get the input elements with certain type. $('input[type=checkbox]') $(':checkbox').on('keypress', function(event) { if (event.which === 13) { $(this).prop('checked', !$(this).prop('checked')); $('textarea').html($(this).prop('checked').toString()); } }); <input type="checkbox" name="Colors" value="Bike" class="mycheckbox">My text<br> $(document).on('keypress', function(event) { if (event.keyCode == 13) { $('#mycheckbox').prop('checked', true); } }); $('input:checkbox').keypress(function(e){ if((e.keyCode ? e.keyCode : e.which) == 13){ $(this).trigger('click'); } }); use preventDefault but pressing Enter would also submit the form. Adding e.preventDefault(); prevents the default browser action when pressing enter on the checkbox. $('input:checkbox').keypress(function(e){ e.preventDefault(); if((e.keyCode ? e.keyCode : e.which) == 13){ $(this).trigger('click'); } }); if (keycode == 13) { $(this).attr('checked', checked); Checkbox_to_RadioButton(this); alert("Enter key was pressed"); } Set the checked state of a checkbox: function check() { document.getElementById("myCheck").checked = true; } function uncheck() { document.getElementById("myCheck").checked = false; } Find out if a checkbox is checked or not: var x = document.getElementById("myCheck").checked; Use a checkbox to convert text in an input field to uppercase: document.getElementById("fname").value = document.getElementById("fname").value.toUpperCase(); Several checkboxes in a form: <form action="/action_page.php"> <input type="checkbox" name="coffee" value="cream">With cream<br> <input type="checkbox" name="coffee" value="sugar">With sugar<br> <br> <input type="button" onclick="myFunction()" value="Send order"> <br><br> <input type="text" id="order" size="50"> <input type="submit" value="Submit"> </form> function myFunction() { var coffee = document.forms[0]; var txt = ""; var i; for (i = 0; i < coffee.length; i++) { if (coffee[i].checked) { txt = txt + coffee[i].value + " "; } } document.getElementById("order").value = "You ordered a coffee with: " + txt; }

    click label check checkbox

    Without jQuery code: use: label for <input type="checkbox" id="Checkbox1"><label for="Checkbox1">Check ME</label> <select id="mySelect" onchange="checkboxes();" />

    window open this children attr

    <p><a href="https://www.youtube.com/channel/Exw">InspirationTuts</a></p> window.open($(this).children("a").attr("href"));

    jquery to change style attribute of a div class

    $('.handle').css('left', '300px');

    jQuery serialize()

    creates a URL encoded text string by serializing form values. $("button").click(function(){ $("div").text($("form").serialize()); }); You can select one or more form elements (like input and/or text area), or the form element itself. The serialized values can be used in the URL query string when making an AJAX request.

    encodeURIComponent() and decodeURIComponent() Function

    decodes a URI component function myFunction() { var uri = "https://w3schools.com/my test.asp?name=ståle&car=saab"; var uri_enc = encodeURIComponent(uri); var uri_dec = decodeURIComponent(uri_enc); var res = "Encoded URI: " + uri_enc + "
    " + "Decoded URI: " + uri_dec; document.getElementById("demo").innerHTML = res; } Encoded URI: https%3A%2F%2Fw3schools.com%2Fmy%20test.asp%3Fname%3Dst%C3%A5le%26car%3Dsaab Decoded URI: https://w3schools.com/my test.asp?name=ståle&car=saab

    to evaluate minutes between time spans

    var d = new Date(); var mins=d.getMinutes(); var hr=d.getHours(); hrdiff = hr - 9; mindiff = mins -30; timespan = hrdiff * 60 + mindiff; if(timespan<60){imgwidth = timespan*22}

    Using Web Workers

    Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. In addition, they can perform I/O using XMLHttpRequest (although the responseXML and channel attributes are always null) or fetch (with no such restrictions). Once created, a worker can send messages to the JavaScript code that created it by posting messages to an event handler specified by that code (and vice versa). the main page: const myWorker = new Worker("my_task.js"); myWorker.onmessage = (event) => { console.log(`Worker said : ${event.data}`); }; myWorker.postMessage("ali"); my_task.js (the worker): postMessage("I'm working before postMessage('ali')."); onmessage = (event) => { postMessage(`Hi, ${event.data}`); };

    Improving Async functions with Web Workers

    Separate the processing part in a different file (possibly ‘my_worker.js’), create a worker with newWorker = new Worker('my_worker.js'); and offload the processing to it. // my_worker.js const do_a_lot_of_processing = (data) => { .... } onmessage = (e) => { postMessage(do_a_lot_of_processing(e.data)); // main.js const myWorker = new Worker('my_worker.js'); async function get_useful_data() { const raw_data = await request(some_url); myWorker.postmessage(raw_data); const show_data => (e) { const data = e.data; ... myWorker.onmessage(show_data); get_useful_data();

    HTML5 Web Workers

    A web worker is a JavaScript running in the background, without affecting the performance of the page. Uncaught DOMException: Failed to construct 'Worker': If you are seeing this in Chrome then the answer probably has to do with loading from a local filesystem rather than over HTTP. The key is the message "cannot be accessed from origin 'null'" It's because Chrome doesn't let you load web workers when running scripts from a local file. run a server, Wampserver64, open browser, run: http://localhost/test web worker.html Limitations Of Web Workers The Web Workers API is a very powerful tool, but it has a few limitations: A worker can’t directly manipulate the DOM and has limited access to methods and properties of the window object. A worker can not be run directly from the filesystem. It can only be run via a server.

    Example

    The example below creates a simple web worker that count numbers in the background: Count numbers: <output id="result"></output> <button onclick="startWorker()">Start Worker</button> <button onclick="stopWorker()">Stop Worker</button> <script> var w; function startWorker() { if(typeof(Worker)!=="undefined") { if(typeof(w)=="undefined") { w = new Worker("demo_workers.js"); } w.onmessage = function(event) { document.getElementById("result").innerHTML=event.data; }; } else { document.getElementById("result").innerHTML="Sorry, your browser does not support Web Workers..."; } } function stopWorker() { w.terminate(); w = undefined; } </script>

    Create a Web Worker File

    Now, let's create our web worker in an external JavaScript. Here, we create a script that counts. The script is stored in the "demo_workers.js" file: var i = 0; function timedCount() { i = i + 1; postMessage(i); setTimeout("timedCount()",500); } timedCount(); The important part of the code above is the postMessage() method - which is used to post a message back to the HTML page. Note: Normally web workers are not used for such simple scripts, but for more CPU intensive tasks.

    Create a Web Worker Object

    Now that we have the web worker file, we need to call it from an HTML page. The following lines checks if the worker already exists, if not - it creates a new web worker object and runs the code in "demo_workers.js": if (typeof(w) == "undefined") { w = new Worker("demo_workers.js"); } Then we can send and receive messages from the web worker. Add an "onmessage" event listener to the web worker. w.onmessage = function(event){ document.getElementById("result").innerHTML = event.data; }; When the web worker posts a message, the code within the event listener is executed. The data from the web worker is stored in event.data.

    Terminate a Web Worker

    When a web worker object is created, it will continue to listen for messages (even after the external script is finished) until it is terminated. To terminate a web worker, and free browser/computer resources, use the terminate() method: w.terminate();

    Reuse the Web Worker

    If you set the worker variable to undefined, after it has been terminated, you can reuse the code: w = undefined;

    Full Web Worker Example Code

    We have already seen the Worker code in the .js file. Below is the code for the HTML page:

    Example

    <!DOCTYPE html> <html> <body> <p>Count numbers: <output id="result"></output></p> <button onclick="startWorker()">Start Worker</button> <button onclick="stopWorker()">Stop Worker</button> <script> var w; function startWorker(){ if(typeof(Worker) !== "undefined") { if(typeof(w) == "undefined") { w = new Worker("demo_workers.js"); } w.onmessage = function(event) { document.getElementById("result").innerHTML = event.data; }; } else { document.getElementById("result").innerHTML = "Sorry! No Web Worker support."; } } function stopWorker() { w.terminate(); w = undefined; } </script> </body> </html>

    Web Workers and the DOM

    Since web workers are in external files, they do not have access to the following JavaScript objects: The window object The document object The parent object building blocks of Web Workers application cases for Web Workers games, graphics, crypto Another use is Web I/O - in other words, polling URLs in background. That way you don't block the UI waiting for polling results. syntax highlighting, which you wouldn’t want to block your code editing whilst you’re using the app. processor-intensive calculations without blocking the user interface thread. As a practical example, think of an app which has a large table

    Types of Web Workers

    It's worth noting that the specification discusses two kinds of Web Workers, Dedicated Workers and Shared Workers. This article will only cover dedicated workers and I'll refer to them as 'web workers' or 'workers' throughout. Web Workers run in an isolated thread. As a result, the code that they execute needs to be contained in a separate file. But before we do that, the first thing to do is create a new Worker object in your main page. The constructor takes the name of the worker script: var worker = new Worker('task.js'); If the specified file exists, the browser will spawn a new worker thread, which is downloaded asynchronously. The worker will not begin until the file has completely downloaded and executed. If the path to your worker returns an 404, the worker will fail silently. After creating the worker, start it by calling the postMessage() method: worker.postMessage(); // Start the worker.

    Communicating with a Worker via Message Passing

    Communication between a work and its parent page is done using an event model and the postMessage() method. Depending on your browser/version, postMessage() can accept either a string or JSON object as its single argument. The latest versions of the modern browsers support passing a JSON object. Below is a example of using a string to pass 'Hello World' to a worker in doWork.js. The worker simply returns the message that is passed to it. Main script: var worker = new Worker('doWork.js'); worker.addEventListener('message', function(e) { console.log('Worker said: ', e.data); }, false); worker.postMessage('Hello World'); // Send data to our worker. doWork.js (the worker): self.addEventListener('message', function(e) { self.postMessage(e.data); }, false); When postMessage() is called from the main page, our worker handles that message by defining an onmessage handler for the message event. The message payload (in this case 'Hello World') is accessible in Event.data. Although this particular example isn't very exciting, it demonstrates that postMessage() is also your means for passing data back to the main thread. Convenient! Messages passed between the main page and workers are copied, not shared. For example, in the next example the 'msg' property of the JSON message is accessible in both locations. It appears that the object is being passed directly to the worker even though it's running in a separate, dedicated space. In actuality, what is happening is that the object is being serialized as it's handed to the worker, and subsequently, de-serialized on the other end. The page and worker do not share the same instance, so the end result is that a duplicate is created on each pass. Most browsers implement this feature by automatically JSON encoding/decoding the value on either end. The following is a more complex example that passes messages using JSON objects. Main script: <button onclick="sayHI()">Say HI</button> <button onclick="unknownCmd()">Send unknown command</button> <button onclick="stop()">Stop worker</button> <output id="result"></output> <script> function sayHI() { worker.postMessage({'cmd': 'start', 'msg': 'Hi'}); } function stop() { // worker.terminate() from this script would also stop the worker. worker.postMessage({'cmd': 'stop', 'msg': 'Bye'}); } function unknownCmd() { worker.postMessage({'cmd': 'foobard', 'msg': '???'}); } var worker = new Worker('doWork2.js'); worker.addEventListener('message', function(e) { document.getElementById('result').textContent = e.data; }, false); </script> doWork2.js: self.addEventListener('message', function(e) { var data = e.data; switch (data.cmd) { case 'start': self.postMessage('WORKER STARTED: ' + data.msg); break; case 'stop': self.postMessage('WORKER STOPPED: ' + data.msg + '. (buttons will no longer work)'); self.close(); // Terminates the worker. break; default: self.postMessage('Unknown command: ' + data.msg); }; }, false); Note: There are two ways to stop a worker: by calling worker.terminate() from the main page or by calling self.close() inside of the worker itself. Example: Run this worker!

    - Transferrable objects

    Most browsers implement the structured cloning algorithm, which allows you to pass more complex types in/out of Workers such as File, Blob, ArrayBuffer, and JSON objects. However, when passing these types of data using postMessage(), a copy is still made. Therefore, if you're passing a large 50MB file (for example), there's a noticeable overhead in getting that file between the worker and the main thread. Structured cloning is great, but a copy can take hundreds of milliseconds. To combat the perf hit, you can use Transferable Objects. With Transferable Objects, data is transferred from one context to another. It is zero-copy, which vastly improves the performance of sending data to a Worker. Think of it as pass-by-reference if you're from the C/C++ world. However, unlike pass-by-reference, the 'version' from the calling context is no longer available once transferred to the new context. For example, when transferring an ArrayBuffer from your main app to Worker, the original ArrayBuffer is cleared and no longer usable. Its contents are (quiet literally) transferred to the Worker context. To use transferrable objects, use a slightly different signature of postMessage(): worker.postMessage(arrayBuffer, [arrayBuffer]); window.postMessage(arrayBuffer, targetOrigin, [arrayBuffer]); The worker case, the first argument is the data and the second is the list of items that should be transferred. The first argument doesn't have to be an ArrayBuffer by the way. For example, it can be a JSON object: worker.postMessage({data: int8View, moreData: anotherBuffer}, [int8View.buffer, anotherBuffer]); The important point being: the second argument must be an array of ArrayBuffers. This is your list of transferrable items. To see the speed improvement of transferrables, check out this DEMO. For more information on transferrables, see our HTML5Rock post.

    - The Worker Environment

    Worker Scope

    In the context of a worker, both self and this reference the global scope for the worker. Thus, the previous example could also be written as: addEventListener('message', function(e) { var data = e.data; switch (data.cmd) { case 'start': postMessage('WORKER STARTED: ' + data.msg); break; case 'stop': ... }, false); Alternatively, you could set the onmessage event handler directly (though addEventListener is always encouraged by JavaScript ninjas). onmessage = function(e) { var data = e.data; ... };

    Features Available to Workers

    Due to their multi-threaded behavior, web workers only has access to a subset of JavaScript's features: The navigator object The location object (read-only) XMLHttpRequest setTimeout()/clearTimeout() and setInterval()/clearInterval() The Application Cache Importing external scripts using the importScripts() method Spawning other web workers Workers do NOT have access to: The DOM (it's not thread-safe) The window object The document object The parent object

    Loading External Scripts

    You can load external script files or libraries into a worker with the importScripts() function. The method takes zero or more strings representing the filenames for the resources to import. This example loads script1.js and script2.js into the worker: worker.js: importScripts('script1.js'); importScripts('script2.js'); Which can also be written as a single import statement: importScripts('script1.js', 'script2.js');

    Subworkers

    Workers have the ability to spawn child workers. This is great for further breaking up large tasks at runtime. However, subworkers come with a few caveats: Subworkers must be hosted within the same origin as the parent page. URIs within subworkers are resolved relative to their parent worker's location (as opposed to the main page). Keep in mind most browsers spawn separate processes for each worker. Before you go spawning a worker farm, be cautious about hogging too many of the user's system resources. One reason for this is that messages passed between main pages and workers are copied, not shared. See Communicating with a Worker via Message Passing. For an sample of how to spawn a subworker, see the example in the specification.

    - Inline Workers

    What if you want to create your worker script on the fly, or create a self-contained page without having to create separate worker files? With Blob(), you can "inline" your worker in the same HTML file as your main logic by creating a URL handle to the worker code as a string: var blob = new Blob([ "onmessage = function(e) { postMessage('msg from worker'); }"]); // Obtain a blob URL reference to our worker 'file'. var blobURL = window.URL.createObjectURL(blob); var worker = new Worker(blobURL); worker.onmessage = function(e) { // e.data == 'msg from worker' }; worker.postMessage(); // Start the worker.

    Blob URLs

    The magic comes with the call to . This method creates a simple URL string which can be used to reference data stored in a DOM File or Blob object. For example: blob:http://localhost/c745ef73-ece9-46da-8f66-ebes574789b1 Blob URLs are unique and last for the lifetime of your application (e.g. until the document is unloaded). If you're creating many Blob URLs, it's a good idea to release references that are no longer needed. You can explicitly release a Blob URLs by passing it to : window.URL.revokeObjectURL(blobURL); In Chrome, there's a nice page to view all of the created blob URLs: chrome://blob-internals/.

    Full Example

    Taking this one step further, we can get clever with how the worker's JS code is inlined in our page. This technique uses a <script> tag to define the worker: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <div id="log"></div> <script id="worker1" type="javascript/worker"> // This script won't be parsed by JS engines // because its type is javascript/worker. self.onmessage = function(e) { self.postMessage('msg from worker'); }; // Rest of your worker code goes here. </script> <script> function log(msg) { // Use a fragment: browser will only render/reflow once. var fragment = document.createDocumentFragment(); fragment.appendChild(document.createTextNode(msg)); fragment.appendChild(document.createElement('br')); document.querySelector("#log").appendChild(fragment); } var blob = new Blob([document.querySelector('#worker1').textContent]); var worker = new Worker(window.URL.createObjectURL(blob)); worker.onmessage = function(e) { log("Received: " + e.data); } worker.postMessage(); // Start the worker. </script> </body> </html> In my opinion, this new approach is a bit cleaner and more legible. It defines a script tag with id="worker1" and type='javascript/worker' (so the browser doesn't parse the JS). That code is extracted as a string using document.querySelector('#worker1').textContent and passed to Blob() to create the file.

    Loading External Scripts

    When using these techniques to inline your worker code, importScripts() will only work if you supply an absolute URI. If you attempt to pass a relative URI, the browser will complain with a security error. The reason being: the worker (now created from a blob URL) will be resolved with a blob: prefix, while your app will be running from a different (presumably http://) scheme. Hence, the failure will be due to cross origin restrictions. One way to utilize importScripts() in an inline worker is to "inject" the current url of your main script is running from by passing it to the inline worker and constructing the absolute URL manually. This will insure the external script is imported from the same origin. Assuming your main app is running from http://example.com/index.html: ... <script id="worker2" type="javascript/worker"> self.onmessage = function(e) { var data = e.data; if (data.url) { var url = data.url.href; var index = url.indexOf('index.html'); if (index != -1) { url = url.substring(0, index); } importScripts(url + 'engine.js'); } ... }; </script> <script> var worker = new Worker(window.URL.createObjectURL(bb.getBlob())); worker.postMessage({url: document.location}); </script>

    - Handling Errors

    As with any JavaScript logic, you'll want to handle any errors that are thrown in your web workers. If an error occurs while a worker is executing, the an ErrorEvent is fired. The interface contains three useful properties for figuring out what went wrong: filename - the name of the worker script that caused the error, lineno - the line number where the error occurred, and message - a meaningful description of the error. Here is an example of setting up an onerror event handler to print the properties of the error: <output id="error" style="color: red;"></output> <output id="result"></output> <script> function onError(e) { document.getElementById('error').textContent = [ 'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message ].join(''); } function onMsg(e) { document.getElementById('result').textContent = e.data; } var worker = new Worker('workerWithError.js'); worker.addEventListener('message', onMsg, false); worker.addEventListener('error', onError, false); worker.postMessage(); // Start worker without a message. </script> Example: workerWithError.js tries to perform 1/x, where x is undefined. workerWithError.js: self.addEventListener('message', function(e) { postMessage(1/x); // Intentional error. };

    - A Word on Security

    Restrictions with Local Access

    Due to Google Chrome's security restrictions, workers will not run locally (e.g. from file://) in the latest versions of the browser. Instead, they fail silently! To run your app from the file:// scheme, run Chrome with the --allow-file-access-from-files flag set. NOTE: It is not recommended to run your primary browser with this flag set. It should only be used for testing purposes and not regular browsing. Other browsers do not impose the same restriction.

    Same Origin Considerations

    Worker scripts must be external files with the same scheme as their calling page. Thus, you cannot load a script from a data: URL or javascript: URL, and an https: page cannot start worker scripts that begin with http: URLs.

    - Use Cases

    So what kind app would utilize web workers? Unfortunately, web workers are still relatively new and the majority of samples/tutorials out there involve computing prime numbers. Although that isn't very interesting, it's useful for understanding the concepts of web workers. Here are a few more ideas to get your brain churning: Prefetching and/or caching data for later use Code syntax highlighting or other real-time text formatting Spell checker Analyzing video or audio data Background I/O or polling of webservices Processing large arrays or humungous JSON responses Image filtering in <canvas> Updating many rows of a local web database

    - Demos

    Example from HTML5Rocks slides Motion tracker Simulated Annealing HTML5demos sample

    - References

    Web Workers specification "Using web workers" from Mozilla Developer Network "Web Workers rise up!" from Dev.Opera

    open multiple pages

    var locs = [ "url1", "url2", ] function multipages() { for (let i = 0; i < locs.length; i++) { window.open(locs[i]) } }

    onmouseover focus and select

    <input type="text" autocomplete="off" name="q" id="query" onmouseover="this.focus()" onfocus="this.select()" value="">

    disable web page certain functions

    jQuery(document).bind("keydown", function(e) { if(e.ctrlKey && (e.which == 44 || e.which == 65 || e.which == 67 || e.which == 73 || e.which == 75 || e.which == 80 || e.which == 88 || e.which == 83 ||e.which == 85)) { e.preventDefault(); return false; } jQuery(document).on( "mousedown", function(event) { if(event.which=="3") { document.oncontextmenu = document.body.oncontextmenu = function() {return false;} } });

    change element attribute

    $("body").on("mouseup", ".unitListItem, .unitHeading", function() { var tab_names = $(this).html().split(","); // change element attribute if ($(this).attr("class") == "unitListItem") { var tab_id = $(this).attr("id"); $(".unitListItem").each(function() { if ($(this).attr("id") != tab_id) { for (tab_name of tab_names) { if ($(this).html().indexOf(tab_name.trim()) >= 0) { $(this).trigger('click'); } } } }); } else if ($(this).attr("class") == "tabtitle unitHeading") { var tab_id = $(this).next().attr("id"); $(".unitHeading").each(function() { if ($(this).next().attr("id") != tab_id) { for (tab_name of tab_names) { if ($(this).html().indexOf(tab_name.trim()) >= 0) { $(this).trigger('click'); } } } }); } });

    turn on/off certain tab and take action

    <button class="tabbut" onclick="openTab('lastrec'); document.getElementById('reqLastRec').submit()" >Last Rec</button> // turn off actionBox $('.actionBox').css('display', 'none');

    Array map() Method

    creates a new array by calling a function on each element. var LongList = ['600004', '600007', '600008', '600009', '600010']; function toACode(thecode) {if (thecode[0]=="6"){ thecode = thecode+".sh" }else { thecode = thecode+".sz" }return(thecode); } newList = LongList.map(item => toACode(item)); find object names: var thisObj = [ { name: 'someName1' }, { name: 'someName2' }, { name: 'someName4' }, { name: 'someName2' } ]; var objNames = thisObj.map(item => item.name);

    Index inside map() function

    get the current iteration's index through 2nd parameter. Example: var list = [ 'h', 'e', 'l', 'l', 'o']; list.map((currElement, index) => { console.log(index, currElement); }); Other arguments of Array.prototype.map(): For example: const array = [1, 2, 3, 4]; const thisObj = { prop1: 1 } const map = array.map((x, index, array) => { console.log(array); console.log(this) }, thisObj); Syntax array.map(function(currentValue, index, arr), thisValue) Parametersb> function() Required. A function to be run for each array element. currentValue Required. The value of the current element. index Optional. The index of the current element. arr Optional. The array of the current element. thisValue Optional. Default value undefined. A value passed to the function to be used as its this value. example to find difference from prev value arr = [1,2,3,2,4,5,6,4,3,2] arr.slice(1).map(function(n, i) { return n - arr[i]; }) [1, 1, -1, 2, 1, 1, -2, -1, -1] example to find difference from two arrays // arr - arr1 var x = arr.map(function(item, index) { return item - arr1[index]; }) console.log(x)

    right click

    1. window.oncontextmenu = function() { showCustomMenu(); return false; // cancel default menu } 2. window.oncontextmenu = function() { alert('Right Click') } // the context menu will still come up // add return false; to stop context menu comes up 3. use mousedown $("img").mousedown(function(ev){ if(ev.which == 1) { alert("Left mouse button clicked on myId"); } if(ev.which == 2) { alert("Middle mouse button clicked on myId"); } if(ev.which == 3) { alert("Right mouse button clicked on myId"); } }); The value of which will be: 1 for the left button 2 for the middle button 3 for the right button 4. <div oncontextmenu="javascript:alert('success!');return false;"> Lorem Ipsum </div> onClick is not triggered through right click. right click only trigger onMouseDown onMouseUp and onContextMenu. So "onContextMenu" is the right click event. <div oncontextmenu="myFunction()"> function myFunction() { alert("You right-clicked inside the div!");} A context menu is a menu in a GUI that appears upon user interaction, such as a right-click mouse operation. A context menu offers a limited set of choices that are available in the current state, or context, of the operating system or application. Usually the available choices are actions related to the selected object.

    create a clickable dropdown menu

    <div class="dropdown"> <button onclick="myFunction()">Dropdown</button> <div id="myDropdown" class="dropdown-content"> <a href="#home">Home</a> <a href="#about">About</a> <a href="#contact">Contact</a> </div> </div> /* When the user clicks on the button, toggle between hiding and showing the dropdown content */ function myFunction() { document.getElementById("myDropdown").classList.toggle("show"); } // Close the dropdown if the user clicks outside of it window.onclick = function(event) { if (!event.target.matches('.dropbtn')) { var dropdowns = document.getElementsByClassName("dropdown-content"); var i; for (i = 0; i < dropdowns.length; i++) { var openDropdown = dropdowns[i]; if (openDropdown.classList.contains('show')) { openDropdown.classList.remove('show'); } } } } convert unicode encoding to string Technically doing: String myString = "\u0048\u0065\u006C\u006C\u006F World"; In order to convert it to "Hello" you'll have to parse the text into the separate unicode digits, (take the \uXXXX and just get XXXX) then do Integer.ParseInt(XXXX, 16) to get a hex value and then case that to char to get the actual character. Some code to accomplish this: String str = myString.split(" ")[0]; str = str.replace("\\",""); String[] arr = str.split("u"); String text = ""; for(int i = 1; i < arr.length; i++){ int hexVal = Integer.parseInt(arr[i], 16); text += (char)hexVal; } // Text will now have Hello

    Swap rows with columns of a matrix

    function transpose(a) { return Object.keys(a[0]).map(function(c) { return a.map(function(r) { return r[c]; }); }); } console.log(transpose([ [1,2,3], [4,5,6], [7,8,9] ])); transpose = m => m[0].map((x,i) => m.map(x => x[i]))

    convert Multi-Dimensional Array to HTML Table

    <table id="mytab"></table> var mytab = $('#mytab'); myArr = [ [1,2,3], [4,5,6], [7,8,9] ] for (var row=0; row < myArr.length; row++) { rowItem = $( '<tr>' ); mytab.append( rowItem ); for (var col=0; col < myArr[row].length; col++) { cell = $('<td>' + $(myArr[row])[col] + '</td>') rowItem.append( cell ); } }

    calculate wAve trend range

    transp = transpose(thedrawdata); var mytab = $('#mytab'); // this is the element to show result rowItem = $( '<tr>' ); mytab.append( rowItem ); for (var row=(transp.length-12); row < transp.length; row++) { rowRange = transp[row].slice(3, 8); rowMax = Math.max(...rowRange); rowMin = Math.min(...rowRange); rowDiff = rowMax - rowMin; //cell = $('<td>' + (Math.round(rowMax*1000)/1000) + '</td>') //rowItem.append( cell ); //cell = $('<td>' + (Math.round(rowMin*1000)/1000) + '</td>') //rowItem.append( cell ); cell = $('<td>' + (Math.round(rowDiff*1000)/1000) + '</td>') rowItem.append( cell ); }

    Find difference between consecutive numbers in array

    Use Array methods and Arrow functions: var visitsArr = [38,29,18,29,28,18,24]; var diffs = visitsArr.slice(1).map((x,i)=> x-visitsArr[i]); diffs.forEach((x,i) => console.log( `Visits from day ${i+1} to day ${i+2} increased by ${x}` )); or function diff(visitsArr) { return visitsArr.slice(1).map(function(n, i) { return n - visitsArr[i]; }); } The estimate is ((yi+1)−(yi−1))/((xi+1)−(xi−1)). This is just the slope between the (i−1)-th point and the the (i+1)-th point.

    sorttable: Make tables sortable

    sorttable: Make tables sortable three steps: Download the Javascript library Include the Javascript library, <script src="sorttable.js"></script> Give your table a class of "sortable": <table class="sortable"> Note that the library's JavaScript file is called sorttable (two Ts), but the class you add to the table is sortable (one T).

    Convert array of numbers to string

    arr.map(String)

    add comments to stks chart by loading script with json data

    load json data from external js file by script src = stkComments.js myjs.js var theCommentList = {item1: "some", item2: "other"}

    Click to toggle block of message

    <div onclick="myFunction()">Click to toggle appearTab! <span id="myappearTab">A Simple appearTab!</span> </div> <script> // When the user clicks on div, open the appearTab function myFunction() { var appearTab = document.getElementById("myappearTab"); appearTab.classList.toggle("show"); } </script> or onclick load script to show data

    Access nested data structures

    const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] }; to access the name of the second item. data.items // data is an object, use dot data.items[1] // The value is an array, use bracket data.items[1].name // This value is an object, use dot data['items'][1]['name']; //or use all brackets

    the rest parameter syntax ...

    sum = (...args) => { console.log(args.length + " arguments");} sum(1,2,3,3,2,1); //6 arguments

    find repeating names in array of object

    thisObj =[{name:'name1'},{name:'name2'},{name:'name4'},{name:'name2'}]; objNames = thisObj.map(item => item.name); objNames.filter((item, idx)=> objNames.indexOf(item) != idx ) // name2 unable to find repeating names in objects because Object.keys(thisObj) removes duplicates autoamtically use R instead to tackle

    currying function

    Currying in JS
    Currying vs partial application Currying and partial application are two ways of transforming a function into another function with a generally smaller arity. currying function currying 又称部分求值,currying 函数会接收一些参数,然后不会立即求值,而是继续返回一个新函数,将传入的参数通过闭包的形式保存,等到被真正求值的时候,再一次性把所有传入的参数进行求值。 // 普通函数 function add(x,y){ return x + y;} add(1 , 2); // 3 // 函数currying var add = function(x) { return function(y) { return x + y;};}; var increment = add(1); increment(2); // 3 这里我们定义了一个 add 函数,它接受一个参数并返回一个新的函数。 调用 add 之后,返回的函数就通过闭包的方式记住了 add 的第一个参数。 那么,我们如何来实现一个简易的currying 函数呢? function curryIt(fn) { // 参数fn函数的参数个数 var n = fn.length; var args = []; return function(arg) { args.push(arg); if (args.length < n) { return arguments.callee; // 返回这个函数的引用 } else { return fn.apply(this , args); } }; } function add(a, b, c) { return [a, b, c];} var c = curryIt(add); var c1 = c(1); var c2 = c1(2); var c3 = c2(3); console.log(c3); //[1, 2, 3] 由此我们可以看出,currying 是一种“预加载”函数的方法,通过传递较少的参数,得到一个已经记住了这些参数的新函数,某种意义上讲,这是一种对参数的“缓存”,是一种非常高效的编写函数的方法! add = (x, y) => x + y add(2, 3) //=> 5 currying function add = x => y => x + y same code without arrow functions add = function(x) { return function(y) { return x + y } } In other words add of some number returns a function

    The reduce() method

    The reduce() method reduces the array to a single value. It executes a provided function for each value of the array (from left-to-right). The return value of the function is stored in an accumulator (result/total). arr.reduce(callback, initialValue); Note: reduce() does not execute the function for array elements without values. Note: this method does not change the original array. Subtract the numbers in the array, starting from the left: var numbers = [175, 50, 25]; function myFunc(total, num) { return total - num; } numbers.reduce(myFunc); // 100 var numbers = [15.5, 2.3, 1.1, 4.7]; function getSum(total, num) { return total + Math.round(num); } numbers.reduce(getSum, 0); // 24 The reducer function takes four arguments: arr.reduce(callback( accumulator, currentValue[, index[, array]] )[, initialValue]) Accumulator (acc) Current Value (cur) Current Index (idx) Source Array (src) Samples var data = [29.76, 41.85, 46.5]; var sum = data.reduce( (total, amount)=>{ return total + amount }); sum // 118.11 Find the Maximum Value dates.reduce((max, d) => d > max ? d : max, dates[0]); Suppose you have an array of async functions that you want to execute in series. There is a non-standard promise.series function for this, but you can also do this with reduce(). const functions = [ async function() { return 1; }, async function() { return 2; }, async function() { return 3; } ]; // Chain the function calls in order, starting with an empty promise. // In the end, `res` is equivalent to // `Promise.resolve().then(fn1).then(fn2).then(fn3)` const res = await functions. reduce((promise, fn) => promise.then(fn), Promise.resolve()); res; // 3 Sum of values in an object array let initialValue = 0 let sum = [{x: 1}, {x: 2}, {x: 3}].reduce( (accumulator, currentValue) => accumulator + currentValue.x , initialValue ) console.log(sum) // logs 6 Flatten an array of arrays let flattened = [[0, 1], [2, 3], [4, 5]].reduce( ( accumulator, currentValue ) => accumulator.concat(currentValue), [] ) Counting instances of values in an object let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'] let countedNames = names.reduce(function(allNames, name) { if (name in allNames) { allNames[name]++ } else { allNames[name] = 1 } return allNames }, {}) // countedNames is: // { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 } Grouping objects by a property let people = [ { name: 'Alice', age: 21 }, { name: 'Max', age: 20 }, { name: 'Jane', age: 20 } ]; function groupBy(objectArray, property) { return objectArray.reduce(function(acc, obj) { let key = obj[property] if (!acc[key]) { acc[key] = [] } acc[key].push(obj) return acc }, {}) } let groupedPeople = groupBy(people, 'age') // groupedPeople is: // { // 20: [ // { name: 'Max', age: 20 }, // { name: 'Jane', age: 20 } // ], // 21: [{ name: 'Alice', age: 21 }] // } Bonding arrays contained in an array of objects using the spread operator and initialValue // friends - an array of objects // where object field "books" is a list of favorite books let friends = [{ name: 'Anna', books: ['Bible', 'Harry Potter'], age: 21 }, { name: 'Bob', books: ['War and peace', 'Romeo and Juliet'], age: 26 }, { name: 'Alice', books: ['The Lord of the Rings', 'The Shining'], age: 18 }] // allbooks - list which will contain all friends' books + // additional list contained in initialValue let allbooks = friends.reduce(function(accumulator, currentValue) { return [...accumulator, ...currentValue.books] }, ['Alphabet']) // allbooks = [ // 'Alphabet', 'Bible', 'Harry Potter', 'War and peace', // 'Romeo and Juliet', 'The Lord of the Rings', // 'The Shining' // ] Remove duplicate items in an array let myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd'] let myOrderedArray = myArray.reduce(function(accumulator, currentValue) { if (accumulator.indexOf(currentValue) === -1) { accumulator.push(currentValue) } return accumulator }, []) console.log(myOrderedArray) Replace .filter().map() with .reduce() Using Array.filter() then Array.map() traverses the array twice, but you can achieve the same effect while traversing only once with Array.reduce(), thereby being more efficient. (If you like for loops, you can filter and map while traversing once with Array.forEach()). const numbers = [-5, 6, 2, 0,]; const doubledPositiveNumbers = numbers.reduce((accumulator, currentValue) => { if (currentValue > 0) { const doubled = currentValue * 2; accumulator.push(doubled); } return accumulator; }, []); console.log(doubledPositiveNumbers); // [12, 4] Running Promises in Sequence /** * Runs promises from array of functions that can return promises * in chained manner * * @param {array} arr - promise arr * @return {Object} promise object */ function runPromiseInSequence(arr, input) { return arr.reduce( (promiseChain, currentFunction) => promiseChain.then(currentFunction), Promise.resolve(input) ) } // promise function 1 function p1(a) { return new Promise((resolve, reject) => { resolve(a * 5) }) } // promise function 2 function p2(a) { return new Promise((resolve, reject) => { resolve(a * 2) }) } // function 3 - will be wrapped in a resolved promise by .then() function f3(a) { return a * 3 } // promise function 4 function p4(a) { return new Promise((resolve, reject) => { resolve(a * 4) }) } const promiseArr = [p1, p2, f3, p4] runPromiseInSequence(promiseArr, 10) .then(console.log) // 1200 Function composition enabling piping // Building-blocks to use for composition const double = x => x + x const triple = x => 3 * x const quadruple = x => 4 * x // Function composition enabling pipe functionality const pipe = (...functions) => input => functions.reduce( (acc, fn) => fn(acc), input ) // Composed functions for multiplication of specific values const multiply6 = pipe(double, triple) const multiply9 = pipe(triple, triple) const multiply16 = pipe(quadruple, quadruple) const multiply24 = pipe(double, triple, quadruple) // Usage multiply6(6) // 36 multiply9(9) // 81 multiply16(16) // 256 multiply24(10) // 240 Write map using reduce if (!Array.prototype.mapUsingReduce) { Array.prototype.mapUsingReduce = function(callback, thisArg) { return this.reduce(function(mappedArray, currentValue, index, array) { mappedArray[index] = callback.call(thisArg, currentValue, index, array) return mappedArray }, []) } } [1, 2, , 3].mapUsingReduce( (currentValue, index, array) => currentValue + index + array.length ) // [5, 7, , 10]

    map() Method

    The map() method calls the provided function once for each element in an array, in order. Return an array with the square root of all the values in the original array: var numbers = [4, 9, 16, 25]; numbers.map(Math.sqrt) Multiply all the values in array with 10: var numbers = [65, 44, 12, 4]; function myFunction(num) { return num * 10; } numbers.map(myFunction) Get the full name for each person in the array: var persons = [ {firstname : "Malcom", lastname: "Reynolds"}, {firstname : "Kaylee", lastname: "Frye"}, {firstname : "Jayne", lastname: "Cobb"} ]; function getFullName(item) { var fullname = [item.firstname, item.lastname].join(" "); return fullname; } persons.map(getFullName);

    filter() Method

    The filter() method creates an array filled with all array elements that pass a test (provided as a function). Note: filter() does not execute the function for array elements without values. Note: filter() does not change the original array. Return an array of all the values in the ages array that are 18 or over: var ages = [32, 33, 16, 40]; function checkAdult(age) { return age >= 18; } ages.filter(checkAdult); Return an array of all the values in the ages over 20: var ages = [32, 33, 12, 40]; function checkAdult(age) { return age >= 20; } ages.filter(checkAdult);

    forEach loop



    var myArray = ['a', 'b', 'c', 'd', 'e']; using For loop to call a function for (var i = 0; i < myArray.length; i++) { currentLetter(myArray[i]); } function currentLetter(letter) { console.log('The current letter is: ' + letter); } using forEach loop with a function myArray.forEach(function(value) { console.log('The current letter is: ' + value; }); using the high order function myArray.forEach(currentLetter); forEach is an Array method that we can use to execute a function on each element in an array. It can only be used on Arrays, Maps, and Sets. arr = ['cat', 'dog', 'fish']; arr.forEach(element => { console.log(element); }); // cat // dog // fish arr = [5,4,8,7]; arr.forEach(function(item,index,arr) { console.log("item: " + item + " at index: " + index + " in the array: " + arr); })

    什么是forEach?

    forEach是我们常用的数组遍历方法之一。 在处理异步操作时,forEach可能会让你掉进一些意想不到的“坑”。 forEach 为数组中的每个元素执行一次给定的回调函数,并且总是返回undefined。 不过需要注意的是,类似arguments这样的类数组对象是没有forEach方法的哦。

    基本语法

    arr.forEach(callback(currentValue [, index [, array]])[, thisArg])

    参数详解

    callback:对每个元素执行的回调函数,它可以接受1到3个参数。 currentValue:当前处理的元素,必选。 index:当前处理元素的索引,可选。 array:正在操作的原数组对象,可选。 thisArg:执行回调函数时this的值,默认为全局对象,可选。

    1、forEach() 方法不支持处理异步函数

    forEach() 是一个同步方法,不支持处理异步函数。 如果你在 forEach 中执行一个异步函数,forEach 不会等待异步函数完成,而是会立即处理下一个元素。 这意味着如果你在 forEach 中使用异步函数,异步任务的执行顺序是无法保证的。

    示例代码

    async function test() { let arr = [3, 2, 1]; arr.forEach(async item => { const res = await mockAsync(item); console.log(res); }); console.log('end'); } function mockAsync(x) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(x); }, 1000 * x); }); } test(); 预期结果: 3 2 1 end 实际结果: end 1 2 3 这个例子中,虽然我们希望按顺序输出 3, 2, 1 和 end,但实际结果是 end 先输出,然后才是 1, 2, 3。 这是因为 forEach 不等待异步操作完成。

    解决方法:使用 for...of 循环和 async/await

    为了解决这个问题,我们可以使用 for...of 循环和 async/await 关键字来确保异步操作按顺序完成。

    示例代码

    async function test() { let arr = [3, 2, 1]; for (let item of arr) { const res = await mockAsync(item); console.log(res); } console.log('end'); } function mockAsync(x) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(x); }, 1000 * x); }); } test(); 输出结果: 3 2 1 end 在这个例子中,我们使用 for...of 循环代替 forEach 方法,通过在循环内部使用 await 关键字,确保每个异步操作完成后才处理下一个元素,从而实现了按顺序输出。

    2、异步函数中的错误无法被捕获

    除了不能处理异步函数外,forEach还有另一个重要的限制:它无法捕获异步函数中的错误。 这意味着即使异步函数在执行过程中抛出错误,forEach 仍然会继续进行下一个元素的处理,而不会对错误进行处理。 这种行为可能会导致程序出现意外的错误和不稳定性。

    3、无法中断或跳过forEach循环

    除了无法处理异步函数和捕获错误之外,forEach还有一个限制:它不支持使用break或continue语句来中断或跳过循环。 如果你需要在循环中途退出或跳过某个元素,应该使用其他支持这些语句的方法,例如for循环。

    示例代码

    let arr = [1, 2, 3]; try { arr.forEach(item => { if (item === 2) { throw('error'); } console.log(item); }); } catch(e) { console.log('e:', e); } // 输出结果: // 1 // e: error 在这个例子中,我们尝试通过抛出异常来中断forEach循环。 虽然这种方法在某些情况下有效,但并不是优雅或推荐的做法。

    更好的解决方案:使用 for...of 循环

    相比之下,for...of 循环更灵活,可以使用 break 和 continue 语句来控制循环的执行。

    示例代码

    let arr = [1, 2, 3]; for (let item of arr) { if (item === 2) { break; // 中断循环 } console.log(item); } // 输出结果: // 1 在这个例子中,当遇到元素2时,循环会被中断,从而避免输出2和3。

    4、无法删除自身元素并重置索引

    在forEach中,我们无法控制索引的值,它只是盲目地递增直到超过数组的长度并退出循环。 因此,删除自身元素以重置索引也是不可能的。 来看一个简单的例子:

    示例代码

    let arr = [1, 2, 3, 4]; arr.forEach((item, index) => { console.log(item); // 输出: 1 2 3 4 index++; }); 在这个例子中,forEach遍历数组 arr,输出每个元素的值。 虽然我们尝试在循环内部递增 index,但这并不会影响forEach的内部机制。 forEach中的索引是自动管理的,并且在每次迭代时都会自动递增。

    为什么无法删除元素并重置索引?

    在forEach中,索引的值是由forEach方法内部控制的。 即使我们手动修改索引变量,也不会影响forEach的遍历行为。 更具体地说,当我们试图在 forEach 内部删除元素时,forEach 不会重新计算索引,这会导致一些元素被跳过,或者某些情况下出现未定义的行为。 例如,如果我们尝试删除当前元素:

    错误示范

    let arr = [1, 2, 3, 4]; arr.forEach((item, index) => { if (item === 2) { arr.splice(index, 1); // 尝试删除元素2 } console.log(item); // 输出: 1 2 4 }); console.log(arr); // 输出: [1, 3, 4] 在这个例子中,当我们删除元素2时,forEach并不会重置或调整索引,因此它继续处理原数组中的下一个元素。 这导致元素3被跳过,因为原来的元素3现在变成了元素2的位置。 当元素 2 被删除后,原数组变为 [1, 3, 4],forEach会继续按照原索引顺序进行,因此输出 1, 2, 4,而元素 3 被跳过了。 这是因为元素 3 在 2 被删除后移动到了索引 1 的位置,而forEach的索引已经移动到 2,所以直接输出了删除后的索引 2 位置的新元素 4。

     更好的解决方案:使用for循环

    let arr = [1, 2, 3, 4]; for (let i = 0; i < arr.length; i++) { if (arr[i] === 2) { arr.splice(i, 1); // 删除元素2 i--; // 调整索引 } else { console.log(arr[i]); // 输出: 1 3 4 } } console.log(arr); // 输出: [1, 3, 4]

    5、this 关键字的作用域问题

    在forEach方法中,this关键字指的是调用该方法的对象。 然而,当我们使用常规函数或箭头函数作为参数时,this关键字的作用域可能会出现问题。 在箭头函数中,this关键字指的是定义该函数的对象; 而在常规函数中,this关键字指的是调用该函数的对象。 为了确保this关键字的正确作用域,我们可以使用bind方法来绑定函数的作用域。 以下是一个说明this关键字作用域问题的例子:

    示例代码

    const obj = { name: "Alice", friends: ["Bob", "Charlie", "Dave"], printFriends: function() { this.friends.forEach(function(friend) { console.log(this.name + " is friends with " + friend); }); }, }; obj.printFriends(); 在这个例子中,我们定义了一个名为obj的对象,里面有一个printFriends方法。 我们使用forEach方法遍历friends数组,并使用常规函数来打印每个朋友的名字和obj对象的name属性。 然而,运行这段代码时,输出如下: undefined is friends with Bob undefined is friends with Charlie undefined is friends with Dave 这是因为在forEach方法中使用常规函数时,该函数的作用域不是调用printFriends方法的对象,而是全局作用域。 因此,无法访问obj对象的属性。

    使用bind方法解决

    为了解决这个问题,我们可以使用bind方法来绑定函数的作用域,将其绑定到obj对象。 下面是一个使用bind方法解决问题的例子:

    示例代码

    const obj = { name: "Alice", friends: ["Bob", "Charlie", "Dave"], printFriends: function() { this.friends.forEach( function(friend) { console.log(this.name + " is friends with " + friend); }.bind(this) // 使用bind方法绑定函数的作用域 ); }, }; obj.printFriends(); 运行这段代码,输出如下: Alice is friends with Bob Alice is friends with Charlie Alice is friends with Dave 通过使用bind方法绑定函数的作用域,我们可以正确地访问obj对象的属性。

    使用箭头函数解决

    另一个解决方案是使用箭头函数。 由于箭头函数没有自己的this,它会继承其当前作用域的this。 因此,在箭头函数中,this关键字指的是定义该函数的对象。

    示例代码

    const obj = { name: "Alice", friends: ["Bob", "Charlie", "Dave"], printFriends: function() { this.friends.forEach((friend) => { console.log(this.name + " is friends with " + friend); }); }, }; obj.printFriends(); 运行这段代码,输出如下: Alice is friends with Bob Alice is friends with Charlie Alice is friends with Dave 使用箭头函数,我们可以确保this关键字指向正确的对象,从而正确访问对象的属性。

    6、forEach 的性能低于 for 循环

    forEach 方法虽然使用方便,但在性能方面却逊色于传统的 for 循环。 原因在于 forEach 的函数签名包含参数和上下文,使得其性能低于 for 循环。

    为什么 for 循环更快?

    简单实现:for 循环的实现最为简单,没有额外的函数调用和上下文处理。 减少函数调用栈:forEach 方法每次迭代都会调用一次回调函数,增加了函数调用栈的开销。 上下文处理:forEach 方法需要处理函数的上下文和参数,这些操作都会消耗额外的时间和资源。

    7、跳过已删除或未初始化的项

    forEach方法在遍历数组时会跳过未初始化的值和已删除的值。 这可能会导致一些意想不到的行为。

    跳过未初始化的值

    在数组中,如果某些值未初始化,forEach会直接跳过这些值。 来看下面这个例子: const array = [1, 2, /* 空 */, 4]; let num = 0; array.forEach((ele) => { console.log(ele); num++; }); console.log("num:", num); // 输出结果: // 1 // 2 // 4 // num: 3 在这个例子中,数组中的第三个元素未初始化,forEach直接跳过了它。 因此,虽然数组的长度是4,但实际被遍历的元素只有3个。

    跳过已删除的值

    当在forEach循环中删除数组元素时,forEach会跳过这些已删除的值。 来看下面这个例子: const words = ['one', 'two', 'three', 'four']; words.forEach((word) => { console.log(word); if (word === 'two') { words.shift(); // 删除数组中的第一个元素 'one' } }); // 输出结果: // one // two // four console.log(words); // ['two', 'three', 'four'] 在这个例子中,当遍历到元素 'two' 时,执行了 words.shift(),删除了数组中的第一个元素 'one'。 由于数组元素向前移动,元素 'three' 被跳过,forEach 直接处理新的第三个元素 'four'。

    8、不会改变原数组

    当调用forEach方法时,它不会改变原数组,即它被调用的数组。 然而,传递的回调函数可能会改变数组中的对象。

    示例代码1

    const array = [1, 2, 3, 4]; array.forEach(ele => { ele = ele * 3 }) console.log(array); // [1, 2, 3, 4] 在这个例子中,forEach方法并没有改变原数组。 虽然在回调函数中对每个元素进行了乘3的操作,但这些操作并没有反映在原数组中。 如果希望通过forEach改变原数组,需要直接修改数组元素的值,而不是简单地对元素进行赋值。 示例代码 const numArr = [33, 4, 55]; numArr.forEach((ele, index, arr) => { if (ele === 33) { arr[index] = 999; } }); console.log(numArr); // [999, 4, 55] 在这个例子中,我们通过forEach方法直接修改了数组中的元素,从而改变了原数组。

    示例代码2

    const changeItemArr = [{ name: 'wxw', age: 22 }, { name: 'wxw2', age: 33 }]; changeItemArr.forEach(ele => { if (ele.name === 'wxw2') { ele = { name: 'change', age: 77 }; } }); console.log(changeItemArr); // [{name: "wxw", age: 22}, {name: "wxw2", age: 33}] 在这个例子中,尝试对数组中的对象进行替换操作,但这种方式并不会改变原数组中的对象。

    解决方案:通过索引改变数组中的对象

    为了正确替换数组中的对象,可以通过索引来直接修改数组中的对象。 示例代码 const allChangeArr = [{ name: 'wxw', age: 22 }, { name: 'wxw2', age: 33 }]; allChangeArr.forEach((ele, index, arr) => { if (ele.name === 'wxw2') { arr[index] = { name: 'change', age: 77 }; } }); console.log(allChangeArr); // [{name: "wxw", age: 22}, {name: "change", age: 77}] 在这个例子中,通过索引直接修改数组中的对象,从而实现了对原数组的修改。

    结束

    总结一下,forEach虽然方便,但在一些特定场景下,使用传统的for循环或其他遍历方法可能更适合你的需求。 比如,当你需要精确控制循环流程、处理异步操作或是修改原数组时,for循环往往能提供更高的灵活性和性能。

    Detect Screen Resolution

    Use the window.screen Object: screen.width, screen.height detect the native resolution of a mobile device display (e.g. retina display): multiply the screen width and height with the device pixel ratio: window.screen.width * window.devicePixelRatio window.screen.height * window.devicePixelRatio function getResolution() { alert("Your screen resolution is: " + screen.width + "x" + screen.height + " retina display " + Math.round(window.screen.width * window.devicePixelRatio) + " " + Math.round(window.screen.height * window.devicePixelRatio)); } getResolution(); should leverage the manufacturer's hint via the <meta name="viewport" content="width=device-width"/> or @-ms-viewport {width:device-width} feature. After that, call window.innerWidth Avoid relying on window.devicePixelRatio for anything. Its meaning and the value it returns is currently in a state of flux and anything you make right now based around it will most likely break very soon. Note: Meta viewport only works on Android, iOS, and Windows Phone 8. @-ms-viewport only works (properly) on IE10 Metro and can interfere with proper Meta viewport behavior on Windows Phone 8.

    Useful JavaScript Tips, Tricks and Best Practices

    1 - Don’t forget var keyword when assigning a variable’s value for the first time. Assignment to an undeclared variable automatically results in a global variable being created. Avoid global variables. 2 - use === instead of == The == (or !=) operator performs an automatic type conversion if needed. The === (or !==) operator will not perform any conversion. It compares the value and the type, which could be considered faster than ==. [10] === 10 // is false [10] == 10 // is true '10' == 10 // is true '10' === 10 // is false [] == 0 // is true [] === 0 // is false '' == false // is true but true == "a" is false '' === false // is false 3 - undefined, null, 0, false, NaN, '' (empty string) are all falsy.
    4 - Use Semicolons for line termination The use of semi-colons for line termination is a good practice. You won't be warned if you forget it, because in most cases it will be inserted by the JavaScript parser. For more details about why you should use semi-colons, take a look to this artice: http://davidwalsh.name/javascript-semicolons. 5 - Create an object constructor function Person(firstName, lastName){ this.firstName = firstName; this.lastName = lastName; } var Saad = new Person("Saad", "Mousliki"); 6 - Be careful when using typeof, instanceof and constructor. typeof : a JavaScript unary operator used to return a string that represents the primitive type of a variable, don't forget that typeof null will return "object", and for the majority of object types (Array, Date, and others) will return also "object". constructor : is a property of the internal prototype property, which could be overridden by code. instanceof : is another JavaScript operator that check in all the prototypes chain the constructor it returns true if it's found and false if not. var arr = ["a", "b", "c"]; typeof arr; // return "object" arr instanceof Array // true arr.constructor(); //[] 7 - Create a Self-calling Function This is often called a Self-Invoked Anonymous Function or Immediately Invoked Function Expression (IIFE). It is a function that executes automatically when you create it, and has the following form: (function(){ // some private code that will be executed automatically })(); (function(a,b){ var result = a+b; return result; })(10,20) 8 - Get a random item from an array var items = [12, 548 , 'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' , 2145 , 119]; var randomItem = items[Math.floor(Math.random() * items.length)]; 9 - Get a random number in a specific range This code snippet can be useful when trying to generate fake data for testing purposes, such as a salary between min and max. var x = Math.floor(Math.random() * (max - min + 1)) + min; 10 - Generate an array of numbers with numbers from 0 to max var numbersArray = [] , max = 100; for( var i=1; numbersArray.push(i++) < max;); // numbers = [1,2,3 ... 100] 11 - Generate a random set of alphanumeric characters function generateRandomAlphaNum(len) { var rdmString = ""; for( ; rdmString.length < len; rdmString += Math.random().toString(36).substr(2)); return rdmString.substr(0, len); } 12 - Shuffle an array of numbers var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411]; numbers = numbers.sort(function(){ return Math.random() - 0.5}); /* the array numbers will be equal for example to [120, 5, 228, -215, 400, 458, -85411, 122205] */ A better option could be to implement a random sort order by code (e.g. : Fisher-Yates shuffle), than using the native sort JavaScript function. For more details take a look to this discussion. 13 - A string trim function The classic trim function of Java, C#, PHP and many other language that remove whitespace from a string doesn’t exist in JavaScript, so we could add it to the String object. String.prototype.trim = function(){return this.replace(/^s+|s+$/g, "");}; A native implementation of the trim() function is available in the recent JavaScript engines. 14 - Append an array to another array var array1 = [12 , "foo" , {name "Joe"} , -2458]; var array2 = ["Doe" , 555 , 100]; Array.prototype.push.apply(array1, array2); /* array1 will be equal to [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */ 15 - Transform the arguments object into an array var argArray = Array.prototype.slice.call(arguments); 16 - Verify that a given argument is a number function isNumber(n){ return !isNaN(parseFloat(n)) && isFinite(n); } 17 - Verify that a given argument is an array function isArray(obj){ return Object.prototype.toString.call(obj) === '[object Array]' ; } Note that if the toString() method is overridden, you will not get the expected result using this trick. Or use… Array.isArray(obj); // its a new Array method You could also use instanceof if you are not working with multiple frames. However, if you have many contexts, you will get a wrong result. var myFrame = document.createElement('iframe'); document.body.appendChild(myFrame); var myArray = window.frames[window.frames.length-1].Array; var arr = new myArray(a,b,10); // [a,b,10] // instanceof will not work correctly, myArray loses his constructor // constructor is not shared between frames arr instanceof Array; // false 18 - Get the max or the min in an array of numbers var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411]; var maxInNumbers = Math.max.apply(Math, numbers); var minInNumbers = Math.min.apply(Math, numbers); 19 - Empty an array var myArray = [12 , 222 , 1000 ]; myArray.length = 0; // myArray will be equal to []. 20 - Don’t use delete to remove an item from array Use splice instead of using delete to delete an item from an array. Using delete replaces the item with undefined instead of the removing it from the array. Instead of… var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ]; items.length; // return 11 delete items[3]; // return true items.length; // return 11 /* items will be equal to [12, 548, "a", undefined × 1, 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */ Use… var items = [12, 548 ,'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' ,2154 , 119 ]; items.length; // return 11 items.splice(3,1) ; items.length; // return 10 /* items will be equal to [12, 548, "a", 5478, "foo", 8852, undefined × 1, "Doe", 2154, 119] */ The delete method should be used to delete an object property. 21 - Truncate an array using length Like the previous example of emptying an array, we truncate it using the length property. var myArray = [12 , 222 , 1000 , 124 , 98 , 10 ]; myArray.length = 4; // myArray will be equal to [12 , 222 , 1000 , 124]. As a bonus, if you set the array length to a higher value, the length will be changed and new items will be added with undefined as a value. The array length is not a read only property. myArray.length = 10; // the new array length is 10 myArray[myArray.length - 1] ; // undefined 22 - Use logical AND/ OR for conditions var foo = 10; foo == 10 && doSomething(); // is the same thing as if (foo == 10) doSomething(); foo == 5 || doSomething(); // is the same thing as if (foo != 5) doSomething(); The logical OR could also be used to set a default value for function argument. function doSomething(arg1){ arg1 = arg1 || 10; // arg1 will have 10 as a default value if it’s not already set } 23 - Use the map() function method to loop through an array's items var squares = [1,2,3,4].map(function(val) { return val * val; }); // squares will be equal to [1, 4, 9, 16] 24 - Rounding number to N decimal place var num =2.443242342; num = num.toFixed(4); // num will be equal to 2.4432 NOTE : the toFixed() function returns a string and not a number. 25 - Floating point problems 0.1 + 0.2 === 0.3 // is false 9007199254740992 + 1 // is equal to 9007199254740992 9007199254740992 + 2 // is equal to 9007199254740994 Why does this happen? 0.1 +0.2 is equal to 0.30000000000000004. What you need to know is that all JavaScript numbers are floating points represented internally in 64 bit binary according to the IEEE 754 standard. For more explanation, take a look to this blog post. You can use toFixed() and toPrecision() to resolve this problem. 26 - Check the properties of an object when using a for-in loop This code snippet could be useful in order to avoid iterating through the properties from the object’s prototype. for (var name in object) { if (object.hasOwnProperty(name)) { // do something with name } } 27 - Comma operator var a = 0; var b = ( a++, 99 ); console.log(a); // a will be equal to 1 console.log(b); // b is equal to 99 28 - Cache variables that need calculation or querying In the case of a jQuery selector, we could cache the DOM element. var navright = document.querySelector('#right'); var navleft = document.querySelector('#left'); var navup = document.querySelector('#up'); var navdown = document.querySelector('#down'); 29 - Verify the argument before passing it to isFinite() isFinite(0/0) ; // false isFinite("foo"); // false isFinite("10"); // true isFinite(10); // true isFinite(undefined); // false isFinite(); // false isFinite(null); // true !!! 30 - Avoid negative indexes in arrays var numbersArray = [1,2,3,4,5]; var from = numbersArray.indexOf("foo") ; // from is equal to -1 numbersArray.splice(from,2); // will return [5] Make sure that the arguments passed to splice are not negative. 31 - Serialization and deserialization (working with JSON) var person = {name :'Saad', age : 26, department : {ID : 15, name : "R&D"} }; var stringFromPerson = JSON.stringify(person); /* stringFromPerson is equal to "{"name":"Saad","age":26,"department":{"ID":15,"name":"R&D"}}" */ var personFromString = JSON.parse(stringFromPerson); /* personFromString is equal to person object */ 32 - Avoid the use of eval() or the Function constructor Use of eval or the Function constructor are expensive operations as each time they are called script engine must convert source code to executable code. var func1 = new Function(functionCode); var func2 = eval(functionCode); 33 - Avoid using with() (The good part) Using with() inserts a variable at the global scope. Thus, if another variable has the same name it could cause confusion and overwrite the value. 34 - Avoid using for-in loop for arrays Instead of using… var sum = 0; for (var i in arrayNumbers) { sum += arrayNumbers[i]; } …it’s better to use… var sum = 0; for (var i = 0, len = arrayNumbers.length; i < len; i++) { sum += arrayNumbers[i]; } As a bonus, the instantiation of i and len is executed once because it’s in the first statement of the for loop. Thsi is faster than using… for (var i = 0; i < arrayNumbers.length; i++) Why? The length of the array arrayNumbers is recalculated every time the loop iterates. NOTE : the issue of recalculating the length in each iteration was fixed in the latest JavaScript engines. 35 - Pass functions, not strings, to setTimeout() and setInterval() If you pass a string into setTimeout() or setInterval(), the string will be evaluated the same way as with eval, which is slow. Instead of using… setInterval('doSomethingPeriodically()', 1000); setTimeout('doSomethingAfterFiveSeconds()', 5000); …use… setInterval(doSomethingPeriodically, 1000); setTimeout(doSomethingAfterFiveSeconds, 5000); 36 - Use a switch/case statement instead of a series of if/else Using switch/case is faster when there are more than 2 cases, and it is more elegant (better organized code). Avoid using it when you have more than 10 cases. 37 - Use switch/case statement with numeric ranges Using a switch/case statement with numeric ranges is possible with this trick. function getCategory(age) { var category = ""; switch (true) { case isNaN(age): category = "not an age"; break; case (age >= 50): category = "Old"; break; case (age <= 20): category = "Baby"; break; default: category = "Young"; break; }; return category; } getCategory(5); // will return "Baby" 38 - Create an object whose prototype is a given object It’s possible to write a function that creates an object whose prototype is the given argument like this… function clone(object) { function OneShotConstructor(){}; OneShotConstructor.prototype= object; return new OneShotConstructor(); } clone(Array).prototype ; // [] 39 - An HTML escaper function function escapeHTML(text) { var replacements= {"<": "&lt;", ">": "&gt;","&": "&amp;", """: "&quot;"}; return text.replace(/[<>&"]/g, function(character) { return replacements[character]; }); } 40 - Avoid using try-catch-finally inside a loop The try-catch-finally construct creates a new variable in the current scope at runtime each time the catch clause is executed where the caught exception object is assigned to a variable. Instead of using… var object = ['foo', 'bar'], i; for (i = 0, len = object.length; i <len; i++) { try { // do something that throws an exception } catch (e) { // handle exception } } …use… var object = ['foo', 'bar'], i; try { for (i = 0, len = object.length; i <len; i++) { // do something that throws an exception } } catch (e) { // handle exception } 41 - Set timeouts to XMLHttpRequests You could abort the connection if an XHR takes a long time (for example, due to a network issue), by using setTimeout() with the XHR call. var xhr = new XMLHttpRequest (); xhr.onreadystatechange = function() { if (this.readyState == 4) { clearTimeout(timeout); // do something with response data } } var timeout = setTimeout( function() { xhr.abort(); // call error callback }, 60*1000 /* timeout after a minute */ ); xhr.open('GET', url, true); xhr.send(); As a bonus, you should generally avoid synchronous XHR calls completely. 42 - Deal with WebSocket timeout Generally when a WebSocket connection is established, a server could time out your connection after 30 seconds of inactivity. The firewall could also time out the connection after a period of inactivity. To deal with the timeout issue you could send an empty message to the server periodically. To do this, add these two functions to your code: one to keep alive the connection and the other one to cancel the keep alive. Using this trick, you’ll control the timeout. Add a timerIDvar timerID = 0; function keepAlive() { var timeout = 15000; if (webSocket.readyState == webSocket.OPEN) { webSocket.send(''); } timerId = setTimeout(keepAlive, timeout); } function cancelKeepAlive() { if (timerId) { cancelTimeout(timerId); } } The keepAlive() function should be added at the end of the onOpen() method of the webSocket connection and the cancelKeepAlive() at the end of the onClose() method. 43 - Keep in mind that primitive operations can be faster than function calls. Use VanillaJS. For example, instead of using… var min = Math.min(a,b); A.push(v); …use… var min = a < b ? a : b; A[A.length] = v; 44 - Don’t forget to use a code beautifier when coding. Use JSLint and minification (JSMin, for example) before going live. 45 - JavaScript is awesome: Best Resources To Learn JavaScript Code Academy JavaScript tracks: http://www.codecademy.com/tracks/javascript Eloquent JavaScript by Marjin Haverbeke: http://eloquentjavascript.net/ Advanced JavaScript by John Resig: http://ejohn.org/apps/learn/

    make a beep

    var audioCtx = new (window.AudioContext || window.webkitAudioContext || window.audioContext); //All arguments are optional: //duration of the tone in milliseconds. Default is 500 //frequency of the tone in hertz. default is 440 //volume of the tone. Default is 1, off is 0. //type of tone. sine, square, sawtooth, triangle, and custom. Default sine. //callback to use on end of tone function beep(duration, frequency, volume, type, callback) { var oscillator = audioCtx.createOscillator(); var gainNode = audioCtx.createGain(); oscillator.connect(gainNode); gainNode.connect(audioCtx.destination); if (volume){gainNode.gain.value = volume;} if (frequency){oscillator.frequency.value = frequency;} if (type){oscillator.type = type;} if (callback){oscillator.onended = callback;} oscillator.start(audioCtx.currentTime); oscillator.stop(audioCtx.currentTime + ((duration || 500) / 1000)); };

    Generate Sounds Programmatically

    https://marcgg.com/blog/2016/11/01/javascript-audio/ Produce a Simple Beep First let’s create a very basic beep using a sinusoid. We’ll initiate an audio context, which is the central object for generating sound. Then we’ll create an oscillator producing the sine wave. Finally we connect the oscillator to the context and start. var context = new AudioContext() var o = context.createOscillator() o.type = "sine" o.connect(context.destination) o.start() You’ll notice that the sound produced here is not great. It seems like you let a phone off the hook and when you stop it, you hear a “click” and it’s not pleasant at all. This is because the human hear reacts this way as explained in this great article. Basically when you stop the sound anywhere else than the zero crossing point, you’ll hear this clicking sound. Clicking noise on a sine curve

    Getting Rid Of The Clicking Sound

    The best solution to get rid of this click is to ramp the sine wave down with an exponentional function, using AudioParam.exponentialRampToValueAtTime() as documented here. This time we need to add a gain node to our oscillator. A gain node allows us to change the volume of a signal as explained in this schema from the documentation: Gain node The code to start the sound now looks like this: var context = new AudioContext() var o = context.createOscillator() var g = context.createGain() o.connect(g) g.connect(context.destination) o.start(0) In order to stop the sound we change the gain value, effectively reducing the volume. Note that we don’t ramp down to 0 since there is a limitation in this function where the value has to be positive. g.gain.exponentialRampToValueAtTime( 0.00001, context.currentTime + 0.04 ) As you can hear, the clicking sound is gone! But that’s not the only interesting thing that you can do with this exponential ramp down.

    Set A Ringing Effect

    In the example above, we decided to stop the sound really quickly, in 0.04 seconds. But what happens when we change this X value? g.gain.exponentialRampToValueAtTime(0.00001, context.currentTime + X)

    Hitting Notes

    Giving more time to the sound to fade out gives it a totally different feel. It gets more visible when we start and stop the signal right away: Start and stop quickly Start and stop slowly The first one sounds like a ticking noise when the other sounds like an actual note played on an instrument.

    Various Oscilators

    So far we’ve been using a sine wave for our main signal, but we have other options: Types of oscilators It’s enven more interesting when we start playing around with the type of oscilators by setting o.type = type. Sine Square Triangle Sawtooth

    Playing Actual Notes

    With the previous code, it becomes fairly simple to have a nice sounding note, but what exactly were we playing? That’s when you have to take frequency into account. For instance, the one people know is that A4 is 440Hz, but there are others.

    Note Frequencies in Hz

    With this table, you can easily create a mapping in your code to play any given note using its . For the hackathon I used a simple hash mapping that is available in this gist.
    CC#DEbEFF#GG#ABbB
    016.3517.3218.3519.4520.6021.8323.1224.5025.9627.5029.1430.87
    132.7034.6536.7138.8941.2043.6546.2549.0051.9155.0058.2761.74
    265.4169.3073.4277.7882.4187.3192.5098.00103.8110.0116.5123.5
    3130.8138.6146.8155.6164.8174.6185.0196.0207.7220.0233.1246.9
    4261.6277.2293.7311.1329.6349.2370.0392.0415.3440.0466.2493.9
    5523.3554.4587.3622.3659.3698.5740.0784.0830.6880.0932.3987.8
    6104711091175124513191397148015681661176018651976
    7209322172349248926372794296031363322352037293951
    8418644354699497852745588592062726645704074597902
    To implement this, we just need to add a frequency to our oscilator: var frequency = 440.0 o.frequency.value = frequency If we change with the value of frequency, we can play any note. For instance: 261.6Hz (C4) 440Hz (A4) 830.6Hz (G#5) Mix this with the ramp down timings and different signals, and you start to be able to create more interesting sounds. 174.6Hz (F3) - Square 1109Hz (C#6) - Sawtooth 87.31 Hz (F2) - Triangle Since you scrolled this far, you might be interested in some other things I wrote: Building A Multiplayer 8 Bits Sequencer Trailing Slashes, Github Pages, Jekyll 3 & 404s Vim Configuration From Scratch in 2016 How CSS Animations Can Break Your Tests Some Respect For Legacy Code Tips on Creating a Website From When I Was 12 Enough With The Trolls Please Keep a Changelog For Your Open Source Lib The One Thing That Made Me Switch To Vim Startup & Tech Book Reviews

    Making Music in the Browser

    Making Music in the Browser You'll find a global constructor AudioContext (webkitAudioContext in Chrome 34/35) that unlocks this functionality.

    Oscillators

    One of the main components of this API is the oscillator. If you've used a synthesizer before, you're likely already familiar with this concept. An oscillator produces a sound wave at a set frequency and pattern. This creates notes with different qualities and textures. Many oscillators, including the ones in the Web Audio API, support 4 different waveforms out of the box: sine, triangle, square, and sawtooth. Each has a unique quality that gives synthesizers their distinctive sound. Let's set up an oscillator. We'll set the frequency to 440 and use a sine wave: const context = new AudioContext() const oscillator = context.createOscillator() oscillator.frequency.value = 440 oscillator.type = 'sine' This won't do much without an audio source to output sound to, of course. We can connect the oscillator to our computer's default audio output pretty simply: oscillator.connect(context.destination) We can start and stop our oscillator using oscillator.start() and oscillator.stop(). Not so fast, though! The browser won't allow us to call these methods unless they're triggered by some user interaction first. This is meant to prevent any random website from making noises without users' permission. We'll add a button to the page and trigger our oscillator to play for a second. document.querySelector('button').addEventListener('click', () => { oscillator.start(context.currentTime) setTimeout(() => oscillator.stop(context.currentTime), 1000) }) Clicking the button should produce a tone from your speakers for about a second. If you click the button a second time, though, you won't hear anything. Why not? You should see an error in your console saying that start can't be called more than once on an oscillator. Ok, so now we have to deal with the fact that we can't start an oscillator multiple times. One way to handle this is to create a new oscillator every time we click the button. So, let's move that code into our event handler. const context = new AudioContext() document.querySelector('button').addEventListener('click', () => { const oscillator = context.createOscillator() oscillator.frequency.value = 440 oscillator.type = 'sine' oscillator.connect(context.destination) oscillator.start(context.currentTime) setTimeout(() => oscillator.stop(context.currentTime), 500) })

    Envelopes (Gain)

    Great! Now our button plays a tone every time we click it. But it sounds a bit... robotic. Real instruments don't cut off their sound immediately; instead, they have a natural decrease in volume over time. This is called decay. So, how can we implement decay here? We need to control the volume! In audio synthesis, this is referred to as an envelope. Let's create a volume envelope for our oscillator. const context = new AudioContext() document.querySelector('button').addEventListener('click', () => { const oscillator = context.createOscillator() const envelope = context.createGain() const decayRate = 1.5 // seconds oscillator.frequency.value = 440 oscillator.type = 'sine' envelope.gain.value = 1 oscillator.connect(envelope) envelope.connect(context.destination) oscillator.start(context.currentTime) envelope.gain.exponentialRampToValueAtTime(0.001, context.currentTime + decayRate) setTimeout(() => oscillator.stop(context.currentTime), decayRate * 1000) }) You'll notice that we've made a change to some of our existing code here. Before, we connected the oscillator directly to the audio source. Now, we first connect it to the envelope, and then connect the envelope to the audio source. We've also added a call to exponentialRampToValueAtTime on the envelope's gain node. This method progressively adjusts the gain to a given value over time. The time it expects is a precise moment, in seconds, which we use the currentTime of our AudioContext instance to calculate.

    Musicality

    Now we've got something that sounds a bit more like an instrument than just a beeping noise. So, how do we get from here to something we can play like an instrument? First, we'll need a broader range of notes. Our button is currently playing at the frequency 440, which corresponds to the note A in the fourth octave. If you're familiar with piano music, this is the A above middle C. Mapping note names to frequencies is a bit tedious, so let's pull in a library to solve this problem for us. I recommend . This library has a few different handy features, but importantly for us, it has a module that can translate notes in a range of octaves to their corresponding frequencies. You can use it like this: import {Note} from 'octavian' const {frequency} = new Note('A4') console.log(frequency) // => 440

    Making It Playable

    The next step is to bind a few keyboard keys to play different notes. We'll pull the contents of our previous click handler function into a new function, playNote, that takes a frequency argument. We'll use that argument to set the oscillator's frequency instead of hard-coding it to 440: function playNote(frequency) { /* ... */ oscillator.frequency.value = frequency /* ... */ } Next, we'll set up a keypress event on the document to play a range of notes with this function depending on which key is pressed. For simplicity, let's map the home row to the octave of middle C (C4): const notes = { a: 'C4', s: 'D4', d: 'E4', f: 'F4', g: 'G4', h: 'A4', j: 'B4', k: 'C5' } document.addEventListener('keypress', ({key}) => { const note = notes[key] const {frequency} = new Note(note) playNote(frequency) }) Et voilà: a playable toy keyboard, right here in the browser!

    Conclusion

    This is a simplified example of what's possible with the Web Audio API, but there's a lot I didn't cover here. This API gives us all the tools we need to build a fully functional synthesizer in JavaScript. It supports filters, noise generation, and even custom waveform creation. I highly recommend looking at MDN's article on using the Web Audio API as a source for more information. With this API being JavaScript, it opens us up to a lot of potential for creativity. What would it be like to combine Web Audio with websockets? What about adding a little randomization to your sounds? The possibilities are endless. I look forward to seeing what you create!

    Understanding typeof, instanceof and constructor in JavaScript

    Some types in JavaScript are so-called “primitive types”, and they don't act like objects. These types are: Undefined Null Boolean Number String The confusion comes from the fact that the boolean, number and string types can be treated like objects in a limited way. For example, the expression "I'm no object".length returns the value 13. This happens because when you attempt to access properties or methods on a primitive value, JavaScript instantiates a wrapper object temporarily, just so you can access its methods. ‘Cause JavaScript's nice like that. I'm not going to go into more details here, but Angus Croll wrote about The Secret Life of JavaScript Primitives, so that would be a good place to learn more.

    typeof

    typeof is a unary operator, just like the ! operator. It returns a string representing the type of its operand. Here are some examples: typeof 3; // returns "number" typeof 'blah'; //returns "string" typeof {}; //returns "object" typeof []; //returns "object" typeof function() {}; //returns "function" typeof has its idiosyncrasies. For example, typeof null returns "object", and typeof /[a-z]/ returns "function". Again, Angus Croll has written more on this subject than I have space for here. So, basically typeof is used for telling apart the different primitive types (as long as you don't care about null). It's no use for telling different types of object apart though – for most objects typeof will return "object".

    constructor

    constructor is a property available on all objects' prototypes, and it is a reference to the constructor function used to create the object. So, ({}).constructor returns the Object constructor function(the parentheses are needed to clarify a syntactic ambiguity) and [].constructor returns the Array constructor function. Likewise, it will return your custom constructor function: function Person(name) { this.name = name; } var dave = new Person('Dave'); dave.constructor === Person; //true Remember that unlike the typeof operator, constructor returns a reference to the actual function. Another gotcha: because constructor is part of the prototype, if you reassign the prototype to a constructor function, e.g. Person.prototype = {};, you'll lose the constructor property.

    instanceof

    instanceof is a binary operator – its syntax is instance instanceof Constructor. So, to continue the above example: dave instanceof Person; //true The difference between instanceof and the constructor property (apart from the obvious syntactic difference) is that instanceof inspects the object's prototype chain. So, going back to our friend dave again: dave instanceof Object; //true This is because Person.prototype is an object, so Object is in dave‘s prototype chain, therefore dave is an instance of Object.

    Wrap-up

    So, if you're dealing with primitive objects, use typeof to distinguish them. Because typeof returns "function" for functions, it can also be useful for checking if an object member or a function argument is a function. If you're working out the constructor of an object, use its constructor property. And if you're dealing with lengthy inheritance chains, and you want to find out whether an object inherits from a certain constructor, use instanceof.

    window.onload vs document.onload

    window.onload By default, it is fired when the entire page loads, including its content (images, CSS, scripts, etc.). document.onload It is called when the DOM is ready which can be prior to images and other external content is loaded. window.onload appears to be the most widely supported. $(document).ready(function() { /* code here */ }); $(function() { /* code here */ });

    jQuery Methods

    www.tutorialsteacher.com/jquery/jquery-methods
    Category Description Imp Methods
    DOM Manipulation These methods manipulate DOM elements in some manner e.g. changing attribute, style attribute, adding and removing elements etc. after(), append(), attr(), before(), more..
    Traversing These methods help in navigating from DOM element to another element in a parent child hierarchy e.g. finding ancestors, descendants or sibling element of a specified element. children(), closest(), each(), first(), next(), filter(), parent(), siblings(), more..
    CSS These methods get and set css related properties of elements. addClass(), css(), hasClass(), removeClass(), toggleClass() more..
    Attributes These methods get and set DOM attributes of elements. attr(), html(), removeAttr(), prop(), val(), more..
    Events These methods are used to handle DOM or JavaScript events. bind(), blur(), change(), click(), dblclick(), focus(), keyup(), keydown(), more..
    Effects These methods are used to add animation to elements. animate(), fadeIn(), fadeOut(), hide(), show(), stop(), more..
    Dimensions These methods are used to get and set the CSS dimensions for the various properties. height(), width(), innerHeight(), innerWidth(), more..
    Forms These methods and event handlers handle forms and their various elements. blur(), change(), val(), submit(), more..
    Ajax These methods allow Ajax functionalities with jQuery e.g. get(), getJson(), post(), load(), more..
    Core These methods are core methods in jQuery API. jQuery(), holdReady(), when(), more..
    Data These methods allow us to associate arbitrary data with specific DOM elements. data(), removeData(), queue(), dequeue(), clearQueue(), more..
    Miscellaneous These methods are useful in various tasks e.g. traversing elements, converting to array etc. each(), index(), get(), toArray(), more..
    Utilities Utility methods are helpful in getting information on various things e.g. browser, function, array, window etc. inArray(), isArray(), isFunction(), isNumeric(), isWindow(), isXmlDoc(), more..

    get mac address

    https://npmjs.org/package/getmac get mac address using windows operating system, following code may help you to get HDD and CPU serial number: var sys = require('util') var exec = require('child_process').exec; function puts(error, stdout, stderr) { console.log(stdout) } exec("wmic CPU get ProcessorId", puts); exec("wmic DISKDRIVE get SerialNumber", puts); to save this serial number to a variable I want its value If I try to console.log(stdout.SerialNumber) then it gives me undefined Perhaps the fingerprintjs2 is one of the solutions for this issue: http://valve.github.io/fingerprintjs2/ https://github.com/Valve/fingerprintjs2 Browser allows very limited access to hardware. If you want to uniquely identify your clients, you can use the below chrome extension. https://github.com/Antony007/ADNIdentifier

    The require() function is not a client side function

    Typically require() is used in server side NodeJS code, but there is a require.js library file https://stackoverflow.com/questions/23603514/javascript-require-function-giving-referenceerror-require-is-not-defined Client on node: require is not defined You have three options: 1. Use <script> tag. 2. Use a CommonJS implementation. Synchronous dependencies like Node.js 3. Use an AMD implementation. CommonJS client side-implementations include: (most of them require a build step before you deploy) 1. Browserify - You can use most Node.js modules in the browser. This is my personal favorite. 2. Webpack - Does everything (bundles JS, CSS, etc). Made popular by the surge of React.js. Notorious for its difficult learning curve. 3. Rollup - New contender. Leverages ES6 modules. Includes tree-shaking abilities (removes unused code). AMD implementations include: RequireJS - Very popular amongst client-side JavaScript developers. Not my taste because of its asynchronous nature. Note, in your search for choosing which one to go with, you'll read about Bower. Bower is only for package dependencies and is unopinionated on module definitions like CommonJS and AMD.

    require()

    When you're first starting out with Node js, it might be a bit confusing because you are most likely accustomed to writing JavaScript code for the web browser. When Node js is the server, the syntax is similar but there are a few differences around how other JavaScript files and modules are included. When writing on the server side you may include files as follows: require('./mysharedfile');. This however is not valid on the client-side. I've previously written an article about Include a JavaScript file in another file. Another good thing to remember is that when you are writing your Node js server-side code you split it into multiple files; ideally one per module keeping the single responsibility principle in mind. This is also good practice when you are doing client-side development as well. Don't be afraid about making a lot of JavaScript files, just be sure that you implement a JavaScript minify so that all of your JavaScript is compiled into a single file and it actually removes the entire need to even used the require();.

    open url target _self

    window.open target _self v window.location.href window.location.href = "webpage.htm"; location.href = "webpage.html"; window.open("url","_self"); window.open("webpage.htm", "_self");

    Access object properties within object

    var settings = { user:"someuser", password:"password", country:"Country", birthplace:country } settings.birthplace = settings.country; You can't access the object inside of itself. You can use variable: var country = "country"; var settings = { user:"someuser", password:"password", country:country, birthplace:country }

    use a constructor function to reference an object during initialization

    This example uses an anonymous function as a constructor. The new object is reference with this. var settings = new function() { this.user = "someuser"; this.password = "password"; this.country = "Country"; this.birthplace = this.country; }; Enumerate the properties of an object there are three native ways to list/traverse object properties: for...in loops Object.keys(o) Object.getOwnPropertyNames(o)

    Accessing Nested Objects in JavaScript

    Accessing Nested Objects Cannot read property 'labels' of undefined const user = { id: 101, email: 'jack@dev.com', personalInfo: { name: 'Jack', address: { line1: 'westwish st', line2: 'washmasher', city: 'wallas', state: 'WX' } } } To access the name of the our user: const name = user.personalInfo.name; const userCity = user.personalInfo.address.city; But, for some reason, if our user’s personal info is not available, the object structure will be like this, const user = { id: 101, email: 'jack@dev.com' } The usual way how most devs deal with this scenario is, const name = user && user.personalInfo ? user.personalInfo.name : null; // undefined error will NOT be thrown as we check for existence before access This is okay if your nested structure is simple, but if you have your data nested 5 or 6 levels deep, then your code will look really messy like this, let city; if ( data && data.user && data.user.personalInfo && data.user.personalInfo.addressDetails && data.user.personalInfo.addressDetails.primaryAddress ) { city = data.user.personalInfo.addressDetails.primaryAddress; } There are a few tricks to deal with this messy object structures. Oliver Steele’s Nested Object Access Pattern This is my personal favorite as it makes the code look clean and simple. I picked this style from stackoverflow a while back and it is pretty catchy once you understand how it works. const name = ((user || {}).personalInfo || {}).name; With this notation, you’ll never run into Cannot read property ‘name’ of undefined. You basically check if user exists, if not, you create an empty object on the fly. This way, the next level key will always be accessed from an object that exists or an empty object, but never from undefined. Unfortunately, you cannot access nested arrays with this trick Access Nested Objects Using Array Reduce Array reduce method is very powerful and it can be used to safely access nested objects. const getNestedObject = (nestedObj, pathArr) => { return pathArr.reduce((obj, key) => (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj); } // pass in your object structure as array elements const name = getNestedObject(user, ['personalInfo', 'name']); // to access nested array, just pass in array index as an element the path array. const city = getNestedObject(user, ['personalInfo', 'addresses', 0, 'city']); // this will return the city from the first address item.

    RGraph AJAX functions

    RGraph AJAX functions rgraph ajax With canvas charts, the functions are located in the RGraph.common.core.js file and since this file is necessarily included you don't have to include anything extra to what you normally include in your page.

    Testing and Automation Tools

    API application programming interfaces (APIs) API testing is performed at the message layer API Testing Tutorial Appium Appium is an open source test automation framework for use with native, hybrid and mobile web apps. It drives iOS, Android, and Windows apps using the WebDriver protocol. Appium Database Testing Database Testing Complete Guide ETL ETL stands for Extract-Transform-Load to ensure that the data that has been loaded from a source to the destination after business transformation is accurate. It also involves the verification of data at various middle stages that are being used between source and destination. ETL Testing or Data Warehouse Testing Tutorial Informatica Informatica Powercenter ETL/Data Integration tool is the most widely used tool and in the common term when we say Informatica, it refers to the Informatica PowerCenter tool for ETL. Informatica Mobile with Automation Mobile automation can be done using many tools Mobile automation QC/ALM HP Application LifeCycle Management (ALM) is the latest incarnation of flagship test management tool Quality Center(QC). HP ALM /Quality Center Tutorial UFT/QTP test automation using QTP tool QTP stands for QuickTest Professional helps testers to perform an automated functional testing seamlessly, without monitoring, once script development is complete. QTP Scrum master A scrum master is the facilitator for an agile development team. Scrum is a methodology that allows a team to self-organize and make changes quickly, in accordance with agile principles. The scrum master manages the process for how information is exchanged. https://www.visual-paradigm.com/scrum/what-is-scrum-master/ Selenium Selenium automates browsers Primarily it is for automating web applications for testing purposes web-based administration tasks can be automated Selenium SOAP UI SoapUI is an open-source web service testing application for Simple Object Access Protocol (SOAP) and representational state transfers (REST). web service inspection, invoking, development, simulation and mocking, functional testing, load and compliance testing. SoapUI is cross-platform. SOAP UI

    clean up RGraph

    example of clearing your canvas updating rgraph Index of RGraph demos RGraph.clear(document.getElementById("cvs")); RGraph.Reset(document.getElementById('cvs'))

    to remove an element at that index

    notvisitedList.splice(topicpointer, 1);

    to remove an element at with that value

    var index = notvisitedList.indexOf(topicpointer); notvisitedList.splice(index, 1);

    get href value of an anchor tag

    Use the .prop() method var href = $('a').prop('href'); Use the .text() method. var text = $('a').text(); Use the querySelector() which will return the first anchor tag within the document. Then we can directly access the href property to get the exact value of the href attribute. var href = document.querySelector('a').href; theElement.match(/href="([^"]*)/)[1]; theElement.getAttribute("href"); document.getElementById("aaa").href; var LibDocsList = []; $('a[href*="LibDocs"]').each(function(i) { var anchor = $(this).prop('href'); anchorNumber = i; anchorLength = anchorNumber; LibDocsList.push(anchor); });

    random jump to some pages

    function randomLinkTo() { linkpointer = Math.floor(Math.random() * notvisitedList.length); linkToAddr = LibDocsList[linkpointer] var index = notvisitedList.indexOf(linkpointer); notvisitedList.splice(index, 1); window.open(linkToAddr, "_blank"); } // following code must be at end to allow full page loaded OK var LibDocsList = []; $('a[href*="LibDocs"]').each(function(i) { var anchor = $(this).prop('href'); anchorNumber = i; anchorLength = anchorNumber; LibDocsList.push(anchor); }); var totalLength = LibDocsList.length - 1 var notvisitedList = [...Array(totalLength).keys()];

    add bootstrap table styles to pandoc tables

    <script> function bootstrapStylePandocTables() { $('tr.header').parent('thead').parent('table').addClass('table table-condensed'); } $(document).ready(function() { bootstrapStylePandocTables(); });

    dynamically load mathjax for compatibility with self-contained

    (function() { var script = document.createElement("script"); script.type = "text/javascript"; script.src = "https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"; document.getElementsByTagName("head")[0].appendChild(script); })(); </script>

    HTML Input Examples

    Examples of using JavaScript to access and manipulate HTML input objects.

    Button Object

    Disable a button Find the name of a button Find the type of a button Find the value of a button Find the text displayed on a button Find the id of the form a button belongs to

    Form Object

    Submit a form Reset a form Find the value of each element in a form Find the accepted character set of a form Find the action attribute of a form Find the value of the enctype attribute in a form Find the number of elements in a form Find the method for sending form data Find the name of a form Find the target of a form

    Option and Select Objects

    Disable and enable a dropdown list Get the id of the form that contains the dropdown list Get the number of options in the dropdown list Turn the dropdown list into a multiline list Select multiple options in a dropdown list Display the selected option in a dropdown list Display all options from a dropdown list Display the index of the selected option in a dropdown list Change the text of the selected option Remove options from a dropdown list

    close a window using Javascript

    some browsers will give you a warning Javascript code is; window.close("","_parent","");

    attach script to html

    document.writeln("<script type=\"text/javascript\">"); document.writeln("\"https://secure.\" : \"http://www.\");"); document.writeln("document.write(\"<sc\"+\"ript type='text/javascript' src='\" +"); document.writeln("href="http://statcounter.com/\" target=\"_blank\"><img "); document.writeln("class=\"statcounter\" "); document.writeln("alt=\"web counter\"></a></div></noscript>");

    spread operator

    The spread operator in JavaScript is a useful syntax for adding elements to an array, combining arrays into one larger one, spreading an array inside the arguments of a function, and more. // Concatenating arrays and objects let arr1 = [1,2,3]; let arr2 = [4,5]; let newArray = [...arr1,...arr2]; console.log(newArray); // Output: [ 1, 2, 3, 4, 5 ] // Copying array elements let arr = ["a","b","c"]; let newArray = [...arr]; console.log(newArray); // Output: ["a", "b", "c"] // Expanding arrays let arr = ["a","b"]; let newArray = [...arr,"c","d"]; console.log(newArray); // Output: ["a", "b", "c", "d"] // Merging objects const userBasic = { name: "Jen", age: 22, }; const userMoreInfo = { country: "Argentina", city: "Córdoba", }; const user = {... userBasic, ... userMoreInfo}; // Output: { name: "Jen", age: 22, country: "Argentina", city: "Córdoba" }

    Try fabric JS to convert canvas to svg

    http://jsfiddle.net/Nofiden/3hcyjo0e/2/ fabric-intro SVG.js lightweight library for manipulating and animating SVG HTML JS var canvas = new fabric.Canvas('canvas', { isDrawingMode: true }); //var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); $("#canvas2svg").click(function(){ canvas.isDrawingMode = false; alert(canvas.toSVG()); });

    LocalStorage, sessionStorage

    Web storage objects localStorage and sessionStorage allow to save key/value pairs in the browser. What’s interesting about them is that the data survives a page refresh (for sessionStorage) and even a full browser restart (for localStorage). We already have cookies. Why additional objects? Unlike cookies, web storage objects are not sent to server with each request. Because of that, we can store much more. Most browsers allow at least 2 megabytes of data (or more) and have settings to configure that. Also unlike cookies, the server can’t manipulate storage objects via HTTP headers. Everything’s done in JavaScript. The storage is bound to the origin (domain/protocol/port triplet). That is, different protocols or subdomains infer different storage objects, they can’t access data from each other. Both storage objects provide same methods and properties: setItem(key, value) – store key/value pair. getItem(key) – get the value by key. removeItem(key) – remove the key with its value. clear() – delete everything. key(index) – get the key on a given position. length – the number of stored items. As you can see, it’s like a Map collection (setItem/getItem/removeItem), but also allows access by index with key(index).

    localStorage demo

    The main features of localStorage are: Shared between all tabs and windows from the same origin. The data does not expire. It remains after the browser restart and even OS reboot. For instance, if you run this code… localStorage.setItem('test', 1); …And close/open the browser or just open the same page in a different window, then you can get it like this: alert( localStorage.getItem('test') ); // 1 We only have to be on the same origin (domain/port/protocol), the url path can be different. The localStorage is shared between all windows with the same origin, so if we set the data in one window, the change becomes visible in another one.

    Object-like access

    We can also use a plain object way of getting/setting keys, like this: // set key localStorage.test = 2; // get key alert( localStorage.test ); // 2 // remove key delete localStorage.test; That’s allowed for historical reasons, and mostly works, but generally not recommended, because: If the key is user-generated, it can be anything, like length or toString, or another built-in method of localStorage. In that case getItem/setItem work fine, while object-like access fails: let key = 'length'; localStorage[key] = 5; // Error, can't assign length There’s a storage event, it triggers when we modify the data. That event does not happen for object-like access. We’ll see that later in this chapter.

    Looping over keys

    As we’ve seen, the methods provide “get/set/remove by key” functionality. But how to get all saved values or keys? Unfortunately, storage objects are not iterable. One way is to loop over them as over an array: for(let i=0; i<localStorage.length; i++) { let key = localStorage.key(i); alert(`${key}: ${localStorage.getItem(key)}`); } Another way is to use for key in localStorage loop, just as we do with regular objects. It iterates over keys, but also outputs few built-in fields that we don’t need: // bad try for(let key in localStorage) { alert(key); // shows getItem, setItem and other built-in stuff } …So we need either to filter fields from the prototype with hasOwnProperty check: for(let key in localStorage) { if (!localStorage.hasOwnProperty(key)) { continue; // skip keys like "setItem", "getItem" etc } alert(`${key}: ${localStorage.getItem(key)}`); } …Or just get the “own” keys with Object.keys and then loop over them if needed: let keys = Object.keys(localStorage); for(let key of keys) { alert(`${key}: ${localStorage.getItem(key)}`); } The latter works, because Object.keys only returns the keys that belong to the object, ignoring the prototype.

    Strings only

    Please note that both key and value must be strings. If were any other type, like a number, or an object, it gets converted to string automatically: sessionStorage.user = {name: "John"}; alert(sessionStorage.user); // [object Object] We can use JSON to store objects though: sessionStorage.user = JSON.stringify({name: "John"}); // sometime later let user = JSON.parse( sessionStorage.user ); alert( user.name ); // John Also it is possible to stringify the whole storage object, e.g. for debugging purposes: // added formatting options to JSON.stringify to make the object look nicer alert( JSON.stringify(localStorage, null, 2) );

    sessionStorage

    The sessionStorage object is used much less often than localStorage. Properties and methods are the same, but it’s much more limited: The sessionStorage exists only within the current browser tab. Another tab with the same page will have a different storage. But it is shared between iframes in the same tab (assuming they come from the same origin). The data survives page refresh, but not closing/opening the tab. Let’s see that in action. Run this code… sessionStorage.setItem('test', 1); …Then refresh the page. Now you can still get the data: alert( sessionStorage.getItem('test') ); // after refresh: 1 …But if you open the same page in another tab, and try again there, the code above returns null, meaning “nothing found”. That’s exactly because sessionStorage is bound not only to the origin, but also to the browser tab. For that reason, sessionStorage is used sparingly.

    Storage event

    When the data gets updated in localStorage or sessionStorage, storage event triggers, with properties: key – the key that was changed (null if .clear() is called). oldValue – the old value (null if the key is newly added). newValue – the new value (null if the key is removed). url – the url of the document where the update happened. storageArea – either localStorage or sessionStorage object where the update happened. The important thing is: the event triggers on all window objects where the storage is accessible, except the one that caused it. Let’s elaborate. Imagine, you have two windows with the same site in each. So localStorage is shared between them. You might want to open this page in two browser windows to test the code below. If both windows are listening for window.onstorage, then each one will react on updates that happened in the other one. // triggers on updates made to the same storage from other documents window.onstorage = event => { // same as window.addEventListener('storage', event => { if (event.key != 'now') return; alert(event.key + ':' + event.newValue + " at " + event.url); }; localStorage.setItem('now', Date.now()); Please note that the event also contains: event.url – the url of the document where the data was updated. Also, event.storageArea contains the storage object – the event is the same for both sessionStorage and localStorage, so event.storageArea references the one that was modified. We may even want to set something back in it, to “respond” to a change. That allows different windows from the same origin to exchange messages. Modern browsers also support Broadcast channel API, the special API for same-origin inter-window communication, it’s more full featured, but less supported. There are libraries that polyfill that API, based on localStorage, that make it available everywhere.

    Summary

    Web storage objects localStorage and sessionStorage allow to store key/value in the browser. Both key and value must be strings. The limit is 5mb+, depends on the browser. They do not expire. The data is bound to the origin (domain/port/protocol). localStorage Shared between all tabs and windows with the same origin Visible within a browser tab, including iframes from the same origin sessionStorage Survives browser restart Survives page refresh (but not tab close) API: setItem(key, value) – store key/value pair. getItem(key) – get the value by key. removeItem(key) – remove the key with its value. clear() – delete everything. key(index) – get the key number index. length – the number of stored items. Use Object.keys to get all keys. We access keys as object properties, in that case storage event isn’t triggered. Storage event: Triggers on setItem, removeItem, clear calls. Contains all the data about the operation (key/oldValue/newValue), the document url and the storage object storageArea. Triggers on all window objects that have access to the storage except the one that generated it (within a tab for sessionStorage, globally for localStorage).

    Complete Guide To Node Client-Server Communication

    This covers the following forms of client-server connection: XMLHttpRequest Server-Sent Events WebSocket HTTP/2 Server to server You can check out the complete source code for each implementation here. Before we begin, I should note that there is no one best protocol or API for client/server communication. Every non-trivial application will require a mix of different transports based on a variety of requirements: interaction with the browser cache, protocol overhead, message latency, reliability, type of data transfer, and more. Some protocols may offer low-latency delivery (e.g., Server-Sent Events, WebSocket), but may not meet other critical criteria, such as the ability to leverage the browser cache or support efficient binary transfers in all cases. Here is visualization to help illustrate how XHR, SSE, and WebSockets differ in their implementations. CLIENT SERVER RELATIONSHIP XHR is optimized for “transactional” request-response communication: the client sends the full, well-formed HTTP request to the server, and the server responds with a full response. There is no support for request streaming, and until the Streams API is available, no reliable cross-browser response streaming API. SSE enables efficient, low-latency server-to-client streaming of text-based data: the client initiates the SSE connection, and the server uses the event source protocol to stream updates to the client. The client can’t send any data to the server after the initial handshake. WebSocket is the only transport that allows bidirectional communication over the same TCP connection (Figure 17–2): the client and server can exchange messages at will. As a result, WebSocket provides low latency delivery of text and binary application data in both directions.

    WebSocket Client-Server Demo

    WebSockets is a technology, based on the ws protocol, that makes it possible to establish a continuous full-duplex connection stream between a client and a server. A typical websocket client would be a user’s browser, but the protocol is platform independent. It is the closest API to a raw network socket in the browser. Except a WebSocket connection is also much more than a network socket, as the browser abstracts all the complexity behind a simple API and provides a number of additional services: Connection negotiation and same-origin policy enforcement Interoperability with existing HTTP infrastructure Message-oriented communication and efficient message framing Subprotocol negotiation and extensibility This is a demo shows a demo of a client connecting to a websocket server and sharing data. Here is the server.js of a websocket. 'use strict'; const WebSocketServer = require('ws').Server const wss = new WebSocketServer({ port: 8081 }); wss.on('connection', ((ws) => { ws.on('message', (message) => { console.log(`received: ${message}`); }); ws.on('end', () => { console.log('Connection ended...'); }); ws.send('Hello Client'); })); Here is the client.js of a websocket. console.log('open: '); var ws = new WebSocket("ws://127.0.0.1:8081"); ws.onopen = function(event) { console.log('Connection is open ...'); ws.send("Hello Server"); };ws.onerror = function(err) { console.log('err: ', err); }ws.onmessage = function(event) { console.log(event.data); document.body.innerHTML += event.data + '<br>'; };ws.onclose = function() { console.log("Connection is closed..."); }

    Stream Updates with Server-Sent Events (SSE)

    SSEs are sent over traditional HTTP. That means they do not require a special protocol or server implementation to get working. WebSockets on the other hand, require full-duplex connections and new Web Socket servers to handle the protocol. In addition, Server-Sent Events have a variety of features that WebSockets lack by design such as automatic reconnection, event IDs, and the ability to send arbitrary events.

    Server-Sent Events vs. WebSockets

    Why would you choose Server-Sent Events over WebSockets? Good question. One reason SSEs have been kept in the shadow is because later APIs like WebSockets provide a richer protocol to perform bi-directional, full-duplex communication. Having a two-way channel is more attractive for things like games, messaging apps, and for cases where you need near real-time updates in both directions. However, in some scenarios data doesn’t need to be sent from the client. You simply need updates from some server action. A few examples would be friends’ status updates, stock tickers, news feeds, or other automated data push mechanisms (e.g. updating a client-side Web SQL Database or IndexedDB object store). If you’ll need to send data to a server, XMLHttpRequest is always a friend. Here is the server.js of our Server Sent Event, we will be sending out data to the client every 5 seconds with an updated timestamp via SSE. 'use strict';const http = require('http'); const util = require('util'); const fs = require('fs');http.createServer((req, res) => { debugHeaders(req);if (req.headers.accept && req.headers.accept == 'text/event-stream') { if (req.url == '/events') { sendSSE(req, res); } else { res.writeHead(404); res.end(); } } else { res.writeHead(200, {'Content-Type': 'text/html'}); res.write(fs.readFileSync(__dirname + '/index.html')); res.end(); } }).listen(8000);const sendSSE = (req, res) => { res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' });const id = (new Date()).toLocaleTimeString();setInterval(() => { constructSSE(res, id, (new Date()).toLocaleTimeString()); }, 5000);constructSSE(res, id, (new Date()).toLocaleTimeString()); //res.end(); }const constructSSE = (res, id, data) => { res.write('id: ' + id + '\n'); res.write("data: " + data + '\n\n'); }const debugHeaders = (req) => { util.puts('URL: ' + req.url); for (let key in req.headers) { util.puts(key + ': ' + req.headers[key]); } util.puts('\n\n'); } And here is the client.js which is reference by the index.html on the client side. Notice how the client never sends out a formal request for data with SSE’s. Once the intial connection has been made with the server then the plain text data can be sent to the client as needed! var source = new EventSource('/events'); source.onmessage = function(e) { document.body.innerHTML += e.data + '; };

    XMLHttpRequest (XHR)

    XMLHttpRequest (XHR) is a browser-level API that enables the client to script data transfers via JavaScript. XHR made its first debut in Internet Explorer 5, became one of the key technologies behind the Asynchronous JavaScript and XML (AJAX) revolution, and is now a fundamental building block of nearly every modern web application. XMLHTTP changed everything. It put the “D” in DHTML. It allowed us to asynchronously get data from the server and preserve document state on the client… The Outlook Web Access (OWA) team’s desire to build a rich Win32 like application in a browser pushed the technology into IE that allowed AJAX to become a reality. — Jim Van Eaton Outlook Web Access: A catalyst for web evolution Here I am running a simple Express server with a simple route to send requested data to the Client. 'use strict';var express = require('express'); var app = express();app.use(express.static(`${__dirname}/public`));app.get('/api', function(req, res){ res.send((new Date()).toLocaleTimeString()); });app.listen(3000); Here is the javascript file linked to my index.html on the client side. I am using the baked in XHR methods as opposed to jQuery since I love to use vanilla JavaScript whenever possible. 'use strict' function reqListener (data) { document.body.innerHTML += this.responseText + '<br>'; }setInterval(function() { var oReq = new XMLHttpRequest(); oReq.addEventListener("load", reqListener); oReq.open("GET", "/api"); oReq.send(); }, 3000); In my Github repo, I cover two more use cases not referenced here, server to server communications and HTTP/2. If you are curious about those forms of communication check it out. One word about HTTP/2 before wrapping up. HTTP/2 is the future of Client-Server communication, but it is a protocol built on top of HTTP/1.1 which means that all of these forms of communicating will be still be relevant in the future, just the means that they are transmitted will be updated. As you can see there are a ton of different ways you can send data between a client and server.

    Client-server communication in Node.js

    I would use websockets for this. Once you've set up the connection you can initiate messages from either side. The WS npm package makes this pretty easy. Server example (using the ws npm package): const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); // Set up server wss.on('connection', function connection(ws) { // when client connects // when client sends something ws.on('message', function incoming(message) { console.log('received: %s', message); }); // Send a message ws.send('Hello client!'); }); Client example (no need for any package, it's built-in) : const socket = new WebSocket('ws://localhost:8080'); // Create WebSocket socket.addEventListener('open', function(event) { // Connection opened socket.send('Hello Server!'); }); socket.addEventListener('message', function(event) { // Listen for messages console.log('Message from server ', event.data); }); There are alternatives if you can't use websockets, such as polling (where the client periodically calls the server to see if theres a message), and long-polling (where the server holds a http request open for an artificially long period of time until a message is ready).

    other method: Server side

    http.createServer(function(req, res) { if (req.method == 'GET') { } else if (req.method == 'POST') { var body = ''; req.on('data', function(data) { body += data; }); req.on('end', function() { console.log("We have received your request successfully."); }); } res.end("ok"); })

    four flavors of Object-Oriented Programming

    There are four ways to write Object-Oriented Programming in JavaScript. They are: Using Constructor functions Using Classes Using Objects Linking to Other Objects (OLOO) Using Factory functions

    Using Constructor functions

    Constructors are functions that contain a this keyword. function Human (firstName, lastName) { this.firstName = firstName this.lastName = lastName } this lets you store (and access) unique values created for each instance. You can create an instance with the new keyword. const chris = new Human('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier const zell = new Human('Zell', 'Liew') console.log(zell.firstName) // Zell console.log(zell.lastName) // Liew

    Class syntax

    Classes are said to be the “syntactic sugar” of Constructor functions. As in, Classes are an easier way of writing Constructor functions. There’s serious contention about whether Classes are bad (like this and this). We’re not going to dive into those arguments here. Instead, we’re just going to look at how to write code with Classes and decide whether Classes are better than constructors based on the code we write. Classes can be written with the following syntax: class Human { constructor(firstName, lastName) { this.firstName = firstName this.lastName = lastName } } Notice the constructor function contains the same code as the Constructor syntax above? We need to do this since we want to initialize values into this. (We can skip constructor if we don’t need to initialize values. More on this later under Inheritance). At first glance, classes seem to be inferior to constructors — there’s more code to write! Hold your horses and don’t form a conclusion at this point. We have a lot more to cover. Classes begin to shine later. As before, you can create an instance with the new keyword. const chris = new Human('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier

    Objects Linking to Other Objects (OLOO)

    OLOO was coined and popularized by Kyle Simpson. In OLOO, you define the blueprint as a normal object. You then use a method (often named init, but that isn’t required in the way constructor is to a Class) to initialize the instance. const Human = { init (firstName, lastName ) { this.firstName = firstName this.lastName = lastName } } You use Object.create to create an instance. After creating the instance, you need to run your init function. const chris = Object.create(Human) chris.init('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier You can chain init after Object.create if you returned this inside init. const Human = { init () { // ... return this } } const chris = Object.create(Human).init('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier

    Factory functions

    Factory functions are functions that return an object. You can return any object. You can even return a Class instance or OLOO instance — and it’ll still be a valid Factory function. Here’s the simplest way to create Factory functions: function Human (firstName, lastName) { return { firstName, lastName } } You don’t need new to create instances with Factory functions. You simply call the function. const chris = Human('Chris', 'Coyier') console.log(chris.firstName) // Chris console.log(chris.lastName) // Coyier
    Now that we’ve seen these four OOP setup possibilities, let’s look at how you declare properties and methods on each of them so we can get a little better understanding of working with them before getting to the bigger comparisons we’re trying to make.

    Declaring properties and methods

    Methods are functions declared as an object’s property. const someObject = { someMethod () { /* ... */ } } In Object-Oriented Programming, there are two ways to declare properties and methods: Directly on the instance In the Prototype Let’s learn to do both.

    Declaring properties and methods with Constructors

    If you want to declare a property directly on an instance, you can write the property inside the constructor function. Make sure to set it as the property for this. function Human (firstName, lastName) { // Declares properties this.firstName = firstName this.lastname = lastName // Declares methods this.sayHello = function () { console.log(`Hello, I'm ${firstName}`) } } const chris = new Human('Chris', 'Coyier') console.log(chris)
    Methods are commonly declared on the Prototype because Prototype allows instances to use the same method. It’s a smaller “code footprint.” To declare properties on the Prototype, you need to use the prototype property. function Human (firstName, lastName) { this.firstName = firstName this.lastname = lastName } // Declaring method on a prototype Human.prototype.sayHello = function () { console.log(`Hello, I'm ${this.firstName}`) }
    It can be clunky if you want to declare multiple methods in a Prototype. // Declaring methods on a prototype Human.prototype.method1 = function () { /*...*/ } Human.prototype.method2 = function () { /*...*/ } Human.prototype.method3 = function () { /*...*/ } You can make things easier by using merging functions like Object.assign. Object.assign(Human.prototype, { method1 () { /*...*/ }, method2 () { /*...*/ }, method3 () { /*...*/ } }) Object.assign does not support the merging of Getter and Setter functions. You need another tool. Here’s why. And here’s a tool I created to merge objects with Getters and Setters.

    Declaring properties and methods with Classes

    You can declare properties for each instance inside the constructor function. class Human { constructor (firstName, lastName) { this.firstName = firstName this.lastname = lastName this.sayHello = function () { console.log(`Hello, I'm ${firstName}`) } } }
    It’s easier to declare methods on the prototype. You write the method after constructor like a normal function. class Human (firstName, lastName) { constructor (firstName, lastName) { /* ... */ } sayHello () { console.log(`Hello, I'm ${this.firstName}`) } }
    It’s easier to declare multiple methods on Classes compared to Constructors. You don’t need the Object.assign syntax. You just write more functions. Note: there’s no , between method declarations in a Class. class Human (firstName, lastName) { constructor (firstName, lastName) { /* ... */ } method1 () { /*...*/ } method2 () { /*...*/ } method3 () { /*...*/ } }

    Declaring properties and methods with OLOO

    You use the same process for declaring properties and methods on an instance. You assign them as a property of this. const Human = { init (firstName, lastName) { this.firstName = firstName this.lastName = lastName this.sayHello = function () { console.log(`Hello, I'm ${firstName}`) } return this } } const chris = Object.create(Human).init('Chris', 'Coyier') console.log(chris)
    To declare methods in the prototype, you write the method like a normal object. const Human = { init () { /*...*/ }, sayHello () { console.log(`Hello, I'm ${this.firstName}`) } }

    Declaring properties and methods with Factory functions

    You can declare properties and methods directly by including them in the returned object. function Human (firstName, lastName) { return { firstName, lastName, sayHello () { console.log(`Hello, I'm ${firstName}`) } } }
    You cannot declare methods on the Prototype when you use Factory functions. If you really want methods on the prototype, you need to return a Constructor, Class, or OLOO instance. (Don’t do this since it doesn’t make any sense.) // Do not do this function createHuman (...args) { return new Human(...args) }

    Creating and using constructors

    What are Classes, Objects, and Constructors? Constructors are like regular functions, but we use them with the new keyword. There are two types of constructors: built-in constructors such as Array and Object, which are available automatically in the execution environment at runtime; and custom constructors, which define properties and methods for your own type of object. A constructor is useful when you want to create multiple similar objects with the same properties and methods. It’s a convention to capitalize the name of constructors to distinguish them from regular functions. Consider the following code: function Book() { // unfinished code } var myBook = new Book(); The last line of the code creates an instance of Book and assigns it to a variable. Although the Book constructor doesn’t do anything, myBook is still an instance of it. As you can see, there is no difference between this function and regular functions except that it’s called with the new keyword and the function name is capitalized.

    Determining the type of an instance

    To find out whether an object is an instance of another one, we use the instanceof operator: myBook instanceof Book // true myBook instanceof String // false Note that if the right side of the instanceof operator isn’t a function, it will throw an error: myBook instanceof {}; // TypeError: invalid 'instanceof' operand ({}) Another way to find the type of an instance is to use the constructor property. Consider the following code fragment: myBook.constructor === Book; // true The constructor property of myBook points to Book, so the strict equality operator returns true. Every object in JavaScript inherits a constructor property from its prototype, which points to the constructor function that has created the object: var s = new String("text"); s.constructor === String; // true "text".constructor === String; // true var o = new Object(); o.constructor === Object; // true var o = {}; o.constructor === Object; // true var a = new Array(); a.constructor === Array; // true [].constructor === Array; // true Note, however, that using the constructor property to check the type of an instance is generally considered bad practice because it can be overwritten.

    Custom constructor functions

    A constructor is like a cookie-cutter for making multiple objects with the same properties and methods. Consider the following example: function Book(name, year) { this.name = name; this.year = '(' + year + ')'; } The Book constructor expects two parameters: name and year. When the constructor is called with the new keyword, it assigns the received parameters to the name and year property of the current instance, as shown below: var firstBook = new Book("Pro AngularJS", 2014); var secondBook = new Book("Secrets Of The JavaScript Ninja", 2013); var thirdBook = new Book("JavaScript Patterns", 2010); console.log(firstBook.name, firstBook.year); console.log(secondBook.name, secondBook.year); console.log(thirdBook.name, thirdBook.year); This code logs the following to the console:
    As you can see, we can quickly build a large number of different book objects by invoking the Book constructor with different arguments. This is exactly the same pattern that JavaScript uses in its built-in constructors like Array() and Date().

    The Object.defineProperty() method

    The Object.defineProperty() method can be used inside a constructor to help perform all necessary property setup. Consider the following constructor: function Book(name) { Object.defineProperty(this, "name", { get: function() { return "Book: " + name; }, set: function(newName) { name = newName; }, configurable: false }); } var myBook = new Book("Single Page Web Applications"); console.log(myBook.name); // Book: Single Page Web Applications // we cannot delete the name property because "configurable" is set to false delete myBook.name; console.log(myBook.name); // Book: Single Page Web Applications // but we can change the value of the name property myBook.name = "Testable JavaScript"; console.log(myBook.name); // Book: Testable JavaScript This code uses Object.defineProperty() to define accessor properties. Accessor properties don’t include any properties or methods, but they define a getter to call when the property is read, and a setter to call when the property is written to. A getter is expected to return a value, while a setter receives the value being assigned to the property as an argument. The constructor above returns an instance whose name property can be set or changed, but cannot be deleted. When we get the value of name, the getter prepends the string Book: to the name and returns it.

    Object literal notations are preferred to constructors

    The JavaScript language has nine built-in constructors: Object(), Array(), String(), Number(), Boolean(), Date(), Function(), Error() and RegExp(). When creating values, we are free to use either object literals or constructors. However, object literals are not only easier to read but also faster to run, because they can be optimize at parse time. Thus, for simple objects it’s best to stick with literals: // a number object // numbers have a toFixed() method var obj = new Object(5); obj.toFixed(2); // 5.00 // we can achieve the same result using literals var num = 5; num.toFixed(2); // 5.00 // a string object // strings have a slice() method var obj = new String("text"); obj.slice(0,2); // "te" // same as above var string = "text"; string.slice(0,2); // "te" As you can see, there’s hardly any difference between object literals and constructors. What’s more intersting is that it’s still possible to call methods on literals. When a method is called on a literal, JavaScript automatically converts the literal into a temporary object so that the method can perform the operation. Once the temporary object is no longer needed, JavaScript discards it.

    Using the new keyword is essential

    It’s important to remember to use the new keyword before all constructors. If you accidentally forget new, you will be modifying the global object instead of the newly created object. Consider the following example: function Book(name, year) { console.log(this); this.name = name; this.year = year; } var myBook = Book("js book", 2014); console.log(myBook instanceof Book); console.log(window.name, window.year); var myBook = new Book("js book", 2014); console.log(myBook instanceof Book); console.log(myBook.name, myBook.year); Here’s what this code logs to the console:
    When we call the Book constructor without new, we are in fact calling a function without a return statement. As a result, this inside the constructor points to Window (instead of myBook), and two global variables are created. However, when we call the function with new, the context is switched from global (Window) to the instance. So, this correctly points to myBook. Note that in strict mode this code would throw an error because strict mode is designed to protect the programmer from accidentally calling a constructor without the new keyword.

    Scope-safe constructors

    As we have seen, a constructor is simply a function, so it can be called without the new keyword. But, for inexperienced programmers, this can be a source of bugs. A scope-safe constructor is designed to return the same result regardless of whether it’s called with or without new, so it doesn’t suffer from those issues. Most built-in constructors, such as Object, Regex and Array, are scope-safe. They use a special pattern to determine how the constructor is called. If new isn’t used, they return a proper instance of the object by calling the constructor again with new. Consider the following code: function Fn(argument) { // if "this" is not an instance of the constructor // it means it was called without new if (!(this instanceof Fn)) { // call the constructor again with new return new Fn(argument); } } So, a scope-safe version of our constructor would look like this: function Book(name, year) { if (!(this instanceof Book)) { return new Book(name, year); } this.name = name; this.year = year; } var person1 = new Book("js book", 2014); var person2 = Book("js book", 2014); console.log(person1 instanceof Book); // true console.log(person2 instanceof Book); // true

    Conclusion

    It’s important to understand that the class declaration introduced in ES2015 simply works as syntactic sugar over the existing prototype-based inheritance and does not add anything new to JavaScript. Constructors and prototypes are JavaScript’s primary way of defining similar and related objects. Constructors are like regular functions, but they are used with the new keyword. We saw how constructors enable us to quickly make multiple similar objects with the same properties and methods, and why the instanceof operator is the safest way to determine the type of an instance. Finally, we looked at scope-safe constructors, which can be called with or without new.

    Flappy bird in Javascript with 25 lines of code

    You can write shell scripts in Javascript?!

    Simple Javascript Reduce Tutorial - By making banana bread

    Chrome Inspector Tutorial - [Chrome Developer Tools]

    Javascript Ternary Operator (Short If) Explained

    React.js tutorial - Sliding puzzle game with custom image

    Javascript Every Function explained - by making our own custom implementation

    Simplified Oauth 2.0 Tutorial - Example with Node.js

    Easiest Web Development Setup Tutorial with VS Code

    Vim macros in VS Code Superpowers - Tutorial

    Live Clock Wallpaper in Node.js Tutorial - [Read files with fs, Node Cron job with node-cron]

    Handling multiple Promises in Javascript - [all, allSettled, any, race]

    Code formatting with Pretties as a Github action - Tutorial

    How to Validate JSON in Javascript - Tutorial and Example

    First steps into Functional Programming in Javascript - Composition Example

    Full Video Background Tutorial using Bideo.js - [HTML, CSS, Javascript]

    CSS only Infinitely Scrolling Background | TUTORIAL | [Clamp, Keyframes, Animation]

    What is a Webhook? - Explained simply with fun example - [Home assistant, IFTTT, Geolocation]

    Trading Bot built with Node and Firebase - 100 day profit report

    Build a Game in React with Recoil [Part 3/3] - Inputs & Game Logic

    Learn Javascript the fun way - Live Weather Tab [Geolocation, setInterval, Closures]

    Deno - Where are the packages and compiled files located?

    Build a Game in React with Recoil [Part 2/3] - Populating the World

    Vite - Super fast build tool [Project Setup]

    How to Debug Deno in VS Code

    Build a Game in React with Recoil [Part 1/3] - Creating the World

    Vim in VS Code - [My setup to avoid the mouse]

    Build a GraphQL server in Deno using Oak - [Getting started tutorial]

    React Recoil Todo List with LocalStorage Persistance

    Vanilla Javascript game development - [Othello Burger flipper]

    Deno Tutorial - Getting started [Installation, Hello World, Import, Fetch]

    Tips for writing High Quality Javascript

    Build a Periodic Table from an API in React - [Javascript, CSS]

    HTML Canvas Reference

    The HTML <canvas> tag is used to draw graphics, on the fly, via scripting (usually JavaScript).

    Colors, Styles, and Shadows

    Property Description fillStyle Sets or returns the color, gradient, or pattern used to fill the drawing strokeStyle Sets or returns the color, gradient, or pattern used for strokes shadowColor Sets or returns the color to use for shadows shadowBlur Sets or returns the blur level for shadows shadowOffsetX Sets or returns the horizontal distance of the shadow from the shape shadowOffsetY Sets or returns the vertical distance of the shadow from the shape Method Description createLinearGradient() Creates a linear gradient (to use on canvas content) createPattern() Repeats a specified element in the specified direction createRadialGradient() Creates a radial/circular gradient (to use on canvas content) addColorStop() Specifies the colors and stop positions in a gradient object

    Line Styles

    Property Description lineCap Sets or returns the style of the end caps for a line lineJoin Sets or returns the type of corner created, when two lines meet lineWidth Sets or returns the current line width miterLimit Sets or returns the maximum miter length

    Rectangles

    Method Description rect() Creates a rectangle fillRect() Draws a "filled" rectangle strokeRect() Draws a rectangle (no fill) clearRect() Clears the specified pixels within a given rectangle

    Paths

    Method Description fill() Fills the current drawing (path) stroke() Actually draws the path you have defined beginPath() Begins a path, or resets the current path moveTo() Moves the path to the specified point in the canvas, without creating a line closePath() Creates a path from the current point back to the starting point lineTo() Adds a new point and creates a line to that point from the last specified point in the canvas clip() Clips a region of any shape and size from the original canvas quadraticCurveTo() Creates a quadratic Bézier curve bezierCurveTo() Creates a cubic Bézier curve arc() Creates an arc/curve (used to create circles, or parts of circles) arcTo() Creates an arc/curve between two tangents isPointInPath() Returns true if the specified point is in the current path, otherwise false

    Transformations

    Method Description
    scale() Scales the current drawing bigger or smaller rotate() Rotates the current drawing translate() Remaps the (0,0) position on the canvas transform() Replaces the current transformation matrix for the drawing setTransform() Resets the current transform to the identity matrix. Then runs transform()

    Text

    Property Description font Sets or returns the current font properties for text content textAlign Sets or returns the current alignment for text content textBaseline Sets or returns the current text baseline used when drawing text Method Description fillText() Draws "filled" text on the canvas strokeText() Draws text on the canvas (no fill) measureText() Returns an object that contains the width of the specified text

    Image Drawing

    Method Description drawImage() Draws an image, canvas, or video onto the canvas

    Pixel Manipulation

    Property Description width Returns the width of an ImageData object height Returns the height of an ImageData object data Returns an object that contains image data of a specified ImageData object Method Description createImageData() Creates a new, blank ImageData object getImageData() Returns an ImageData object that copies the pixel data for the specified rectangle on a canvas putImageData() Puts the image data (from a specified ImageData object) back onto the canvas

    Compositing

    Property Description globalAlpha Sets or returns the current alpha or transparency value of the drawing globalCompositeOperation Sets or returns how a new image is drawn onto an existing image

    Other

    Method Description save() Saves the state of the current context restore() Returns previously saved path state and attributes createEvent() getContext() toDataURL()

    Simple linear regression method in javascript

    linear regression function findLineByLeastSquares(values_x, values_y) { var sum_x = 0; var sum_y = 0; var sum_xy = 0; var sum_xx = 0; var count = 0; //We'll use those variables for faster read/write access. var x = 0; var y = 0; var values_length = values_x.length; if (values_length != values_y.length) { throw new Error('The parameters values_x and values_y need to have same size!'); } if (values_length === 0) { return [ [], [] ]; } // Nothing to do. // Calculate the sum for each of the parts necessary. for (var v = 0; v < values_length; v++) { x = values_x[v]; y = values_y[v]; sum_x += x; sum_y += y; sum_xx += x*x; sum_xy += x*y; count++; } // Calculate m and b for the formular: y = x * m + b var m = (count*sum_xy - sum_x*sum_y) / (count*sum_xx - sum_x*sum_x); var b = (sum_y/count) - (m*sum_x)/count; // We will make the x and y result line now var result_values_x = []; var result_values_y = []; for (var v = 0; v < values_length; v++) { x = values_x[v]; y = x * m + b; result_values_x.push(x); result_values_y.push(y); } return [result_values_x, result_values_y]; }

    convert string array to json object

    first line is header strArr =["first second third", "function JSON parse", "JavaScript function JSON", "into a JavaScript",] function tsvToJson(strArr) { var header = strArr[0].split("\t") var headerLength = header.length var resultObj = [] for (var i = 1; i < strArr.length; i++ ) { // start from second line var tempObj = {}; var data = strArr[i].split("\t") for ( k = 0; k < headerLength; k++ ) { tempObj[header[k]] = data[k]; } resultObj.push(tempObj); } return resultObj; }

    hide script away from document

    https://stackoverflow.com/questions/18313770/can-i-store-javascript-in-a-local-storage-object-and-run-it

    to append script to document by appendChild

    var script = document.createElement('script'); script.src = 'data:text/javascript,' + encodeURI(myScript); script.onload = function() { //optional callback }; document.body.appendChild(script); This is inserting an actual script tag using a data uri as the source. This way, it will appear under "scripts" on the resources tab of the dev tools. When the script loads, the data uri (your code) will be executed.

    store javascript in Local Storage

    Here are two methods: Method 1: eval() eval(localStorage.myCode); localStorage.myCode = "alert('just a test')"; eval(localStorage.myCode); testScript = `function testadd() {....}` localStorage.setItem("testScript", testScript) eval(localStorage.testScript); You can check if your code is stored like this: if (!localStorage.myCode) { // local storage code not exists, load from somewhere else } else {// perform the eval using the code from local storage} Method 2: the Function constructor new Function(localStorage.myCode)(); Here are the jsfiddle demos showing that they all work: Method 1: http://jsfiddle.net/markasoftware/3BkAV/ Method 2: http://jsfiddle.net/markasoftware/j6JAz/

    string manipulations

    // remove last character string.slice(0, -1) // extract sub string string = "asd/asdf" string.substring(string.indexOf("/"), string.length); // /asdf string.substring(string.indexOf("/")+1, string.length); // asdf string = "asd/asdf/fds" string.substring( string.indexOf("/") + 1, string.lastIndexOf("/")) // asdf string = "asd/asdf/fds/taeg/hjk" // to select asdf by split method sections = string.split("/") sections[1] // asdf substring processing: //str = 'asdfghjkl'; //str.substring(0,3); // shows 'asd' //str.substring(3); // fghjkl

    build your own proxy

    The same origin policy is not enforced within server-to-server communication. In addition, you eliminate the latency concern. You don’t need to share the cors-anywhere proxy with other consumers, and you can dedicate as many resources as you need to your own servers. Here’s some quick Node.js code that uses the express web framework to create a proxy server around the same https://joke-api-strict-cors.appspot.com/ from above: const express = require('express'); const request = require('request'); const app = express(); app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); next(); }); app.get('/jokes/random', (req, res) => { request( { url: 'https://joke-api-strict-cors.appspot.com/jokes/random' }, (error, response, body) => { if (error || response.statusCode !== 200) { return res.status(500).json({ type: 'error', message: err.message }); } res.json(JSON.parse(body)); } ) }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => console.log(`listening on ${PORT}`)); If you want to see this in action, head to the source code for the above, along with relevant steps in the README: https://github.com/15Dkatz/beat-cors-server How does this work? The proxy uses express middleware to apply a Access-Control-Allow-Origin: * header to every response from the server. At its own jokes/random GET endpoint, the proxy requests a random joke from another server. The same-origin policy doesn’t step in to block the request, even though the domains are different. After all, this is a server-to-server request. Finally, the proxy creates a response to the original requester (an app on the browser) consisting of the resulting data and the middleware-applied Access-Control-Allow-Origin: * header. Build a Node.js Proxy Server

    Tips

    if then else var age = 50 age < 21 ? console.log("child") : console.log("adult") number to string age = 50 console.log(typeof age) age = 50 + "" console.log(typeof age) Fill arrays users = Array(5); // 5 empty items users = Array(5).fill(""); // 5 empty strings users = Array(5).fill(5); // 5 numbers of value 5 Unique Arrays users = ["a","b","c","d","e","b"] unique = Array.from(new Set(users)) Dynamic Objects dynamic = 'hobbies'; user = { name:"Ed", email:"abc@aol.com", [dynamic]:"sleep" } Slicing Arrays users = [1,2,3,4,5,6,7,8] users.length = 3 // force only first 3 items included Slicing Arrays end users.slice(-1) // onlys last one selected users.slice(-3) // onlys last 3 selected CHange array to object users = [1,2,3,4,5,6,7] usersObject = {...users} // converted to objects Object to arrays user = { name:"Ed", email:"abc@aol.com", hobbies:"sleep" } usersKeysArray = Object.keys(user) usersValArray = Object.values(user) Performance startAt = performance.now() // run a long loop endAT = performance.now() console.log(`take ${endAT - startAt} milliseconds`)

    Load external source

    <element onload="myFunction()" src= urlAddr> // body, iframe, img, object function myFunction() { alert("Iframe is loaded."); } <element id="myFrame" src="/default.asp"> document.getElementById("myFrame").addEventListener("load", myFunction); function myFunction() { alert("Iframe is loaded."); } function fetchImages(argument) { var script = document.createElement('script'); script.onload = function(data) { // do something with data // Cross-Origin Read Blocking (CORB) blocked cross-origin response with MIME type text/html }; script.src = argument; document.getElementsByTagName('head')[0].appendChild(script); // or use document.head.append(script); } fetchImages(urlAddr)

    Node.js communicate with client side JavaScript

    By making an HTTP request, with the XMLHttpRequest object, or by generating a <form> and then submitting it, or a variety of other methods, just like any other server side program in a web application.

    find center point of multiple corordinates

    function rad2degr(rad) { return rad * 180 / Math.PI; } function degr2rad(degr) { return degr * Math.PI / 180; } /** * @param latLngInDeg array of arrays with latitude and longtitude * pairs in degrees. e.g. [[latitude1, longtitude1], [latitude2 * [longtitude2] ...] * * @return array with the center latitude longtitude pairs in * degrees. */ function getLatLngCenter(latLngInDegr) { var LATIDX = 0; var LNGIDX = 1; var sumX = 0; var sumY = 0; var sumZ = 0; for (var i=0; i<latLngInDegr.length; i++) { var lat = degr2rad(latLngInDegr[i][LATIDX]); var lng = degr2rad(latLngInDegr[i][LNGIDX]); // sum of cartesian coordinates sumX += Math.cos(lat) * Math.cos(lng); sumY += Math.cos(lat) * Math.sin(lng); sumZ += Math.sin(lat); } var avgX = sumX / latLngInDegr.length;

    find center of multiple points

    * @param array data 2 dimensional array of latitudes and longitudes * For Example: * $data = array * ( * 0 = > array(45.849382, 76.322333), * 1 = > array(45.843543, 75.324143), * 2 = > array(45.765744, 76.543223), * 3 = > array(45.784234, 74.542335) * ); */ function GetCenterFromDegrees(data) { if (!(data.length > 0)){ return false; } var num_coords = data.length; var X = 0.0; var Y = 0.0; var Z = 0.0; for(i = 0; i < data.length; i++){ var lat = data[i][0] * Math.PI / 180; var lon = data[i][1] * Math.PI / 180;

    Declaring global variable within function

    To declare JavaScript global variables inside function, you need to use window object. For example: function m(){ //declaring global variable by window object window.thisglovalue = 100; }

    Optional Chaining

    If you have worked with JavaScript for any amount of time then you have probably seen code that looks just like this. const street = person && person.address && person.address.street The above code is pretty much the shortest and most elegant way to check if an object is undefined or null before accessing its properties. This is obviously not very concise or clean code, though, which is why JavaScript is finally getting an optional chaining operator.

    What Is Optional Chaining

    If you have used other languages besides JavaScript you are probably already familiar with optional chaining since most languages have supported it for awhile. Essentially the idea of optional chaining is to make it easy to write code where you need to access properties or values that are nested deep inside an object or array that may or may not be null/undefined. Let’s take a look at the basic syntax for optional chaining to understand exactly how it works. const name = person?.name In the above code we have a variable person which may or may not be null/undefined. Because we do not know if person is defined we cannot directly access the name property since if person is undefined we would get the following error. Uncaught TypeError: Cannot read property 'name' of undefined By using the optional chaining operator (?.), though, we are able to write our code as if we are directly accessing name. If person is undefined our code will just return undefined instead of throwing an error. Essentially the code above is the same as the following code. const name = person == null ? undefined : person.name The optional chaining operator is checking the person variable to ensure it is defined before access the name property and if it is not defined it will just return undefined. This means we can write the original code for getting the street as follows. const street = person?.address?.street This code is much easier to read then the original code and is one of the greatest use cases for optional chaining. JavaScript does have many additional uses for optional chaining, though, which most other languages do not implement.

    Optional Chaining Functions

    The first big additional use case for optional chaining is doing optional chaining with function calls. Let’s first look at some code for calling a function on an object that may not be defined. const windowCount = house.getWindowCount && house.getWindowCount() This code is essentially checking the house variable to ensure it has a property called getWindowCount before trying to call that function. This code is obviously pretty clunky and difficult to read which is where the optional chaining operator comes in. const windowCount = house.getWindowCount?.() Now at first it may seem weird to have a period (.) before the function parenthesis, but that is because the optional chaining operator is a question mark followed by a period (?.) and not just a question mark. This new code that uses the optional chaining operator will now check if there is a function defined on the house variable called getWindowCount and if it exists it will call it. If that function does not exist on the house variable then it will just return undefined instead of calling the function. This ability to do optional chaining on functions is something that many other languages do not implement and is really handy, especially in JavaScript since functions are used everywhere.

    Optional Chaining Arrays

    The last main way that optional chaining can be used is with arrays. If you want to access an element in an array by index, but are not sure if the array is defined then you need to use code that looks something like this. const firstElement = arr && arr[0] By using the optional chaining operator this code can be simplified to the following. const firstElement = arr?.[0] Again this probably looks weird with a period (.) before the brackets for accessing an array element, but it is just part of the syntax for the optional chaining operator. This new code will work by first checking if the arr variable is defined and if it is it will attempt to access the index of the array specified. If the arr variable is not defined then undefined will be returned instead of trying to access the index of the array. This bracket notation optional chaining can also be used with objects as well. const name = person?.['name'] This is really useful if you want to dynamically access a property of an object based on a string and are not sure if the object is defined.

    Browser Support

    With all great new JavaScript features the biggest thing to worry about is browser support. Unfortunately, the optional chaining operator has very little support outside of the newest browsers. At the time of writing this article the optional chaining operator only has 45% support across browsers. Luckily, though, you can still use this operator by using tools like babel to transpile your JavaScript code so that older browsers can understand it.

    Conclusion

    The optional chaining operator is something that most other languages have had the luxury of using for years, but is only just now being introduced into JavaScript. This means that most browsers still have not implemented this feature, but with the power of tools like babel this feature can be used right now without having to worry about browser support. I highly recommend using this operator in all your new projects that have babel since it will make writing clean JavaScript much easier.

    convert 2-dimensional array to object

    var myArray = [ [12,2,"copy"], [13,5,"copy"], [18,-1,"original"], ] var json = [ {docId: 12, userId: 2, type: "copy"}, {docId: 13, userId: 5, type: "copy"}, {docId: 18, userId: -1, type: "original"} ] json = myArray.map(function(x) { return { "s_id": x[0], "t_id": x[1], "type": x[2] } })

    machine Learning

    javascript machineLearning

    DevTools failed to load SourceMap

    : Could not load content for https://unpkg.com/brain-browser.min.js.map Chrome complains about a missing source map

    encription

    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script> <label>encrypted</label> <div id="demo1"></div> <label>decrypted</label> <div id="demo2"></div> <label>Actual Message</label> <div id="demo3"></div> <script> var encrypted = CryptoJS.AES.encrypt("williamkpchan", "Secret Passphrase"); var decrypted = CryptoJS.AES.decrypt(encrypted, "Secret Passphrase"); document.getElementById("demo1").innerHTML = encrypted; document.getElementById("demo2").innerHTML = decrypted; document.getElementById("demo3").innerHTML = decrypted.toString(CryptoJS.enc.Utf8); </script> Encrypted is actually an object, encrypted.toString() to get the string. https://stackoverflow.com/questions/18279141/javascript-string-encryption-and-decryption

    array addition

    adata = [1,2,3] bdata = [3,4,5] thedrawdata=[] thedrawdata.push(adata) thedrawdata.push(bdata) thedrawdata[2] = thedrawdata[0].map(function(a, i) { return a + thedrawdata[1][i]; }); console.log(thedrawdata[0],thedrawdata[1],thedrawdata[2]) var arr = [1,2,3,4]; var arr2 = [1,1,1,2]; var squares = arr.map((a, i) => a + arr2[i]); console.log(squares);

    convert a string to function name

    var myString = "echoHello"; window[myString] = function() { alert("Hello!"); } echoHello();

    create indirect variable

    var myString = "thisvariable"; window[myString] = "what" thisvariable var rvListName = "removeList" window[rvListName] = window["bookid"] + " rvList" rMList = localStorage.getItem(removeList)

    convert all elements in array to interger

    rMList = rMList.map(Number); removeList = "revList" rMList = [1,3] localStorage.setItem(removeList, rMList) rMList = localStorage.getItem(removeList).split(",").map(Number)

    convert num string to weekday

    const str = "20210620"; function parse(str) { var y = str.substr(0,4), m = str.substr(4,2) - 1, d = str.substr(6,2); var D = new Date(y,m,d); return (D.getFullYear() == y && D.getMonth() == m && D.getDate() == d) ? D : 'invalid date'; } const day = ["sun","mon","tue","wed","thu","fri","sat"][parse(str).getDay()] console.log(day)

    script to close a message on web page

    <div class="alert"> <span onclick="this.parentElement.style.display='none';">×</span> </div> Use the HTML entity "×" to create the letter "x".

    to make window scroll to location with offset

    #startpt { scroll-margin-top: 100px;} if(testkey == "l"){window.location = '#startpt';} also try: (function() { if (document.location.hash) { setTimeout(function() { window.scrollTo(window.scrollX, window.scrollY - 100); }, 10); } })();

    Errors - Throw and Try to Catch

    The try statement lets you test a block of code for errors. The catch statement lets you handle the error. The throw statement lets you create custom errors. The finally statement lets you execute code, after try and catch, regardless of the result. This example demonstrates how to use catch to diplay an error. adddlert is not defined try { adddlert("Welcome guest!");} catch(err) { document.getElementById("demo").innerHTML = err.message;} check storage: try{localStorage.setItem('check_storage','local storage');window.supportLS=true;}catch(e){window.supportLS=false;}

    to convert string to calculation result

    var str = "2*7.1 + 4/0,5"; str = str.replace(',','.'); eval("var answer = "+str); alert(answer); function callCalculator() { str = prompt("Calculation Input:", ""); if (str != null && str != "") { str = str.replace(',','.'); eval("var answer = " + str); alert(answer); } }

    correct setTimeout way

    try it setTimeout(() => { $("#ttt").append(" 1 sec"); }, 1000); setTimeout( $("#ttt").append(" 5 sec"), 5000); setTimeout( $("#ttt").append(" 8 sec"), 8000); setTimeout(() => { $("#ttt").append(" 3 sec"); }, 3000); setTimeout must run a function, not one direct line! chain in setTimeout: setTimeout( function () { $("#logbook").append("First"); setTimeout( function () { $("#logbook").append(" Second"); setTimeout( function () { $("#logbook").append(" Third"); }, 1000); }, 2000); }, 4000); 多次调用异步函数: "函数瀑布" 变得非常冗赘 use Promise to realize it: new Promise(function (resolve, reject) { setTimeout(function () { console.log("First"); resolve(); }, 1000); }).then(function () { return new Promise(function (resolve, reject) { setTimeout(function () { console.log("Second"); resolve(); }, 4000); }); }).then(function () { setTimeout(function () { console.log("Third"); }, 3000); });

    setTimeout with a shorter delay

    setTimeout in most browsers doesn't allow a delay less than about 10 milliseconds (it forces any smaller delays to be longer, Chrome has changed this to 2 milliseconds, though, and apparently had some problems with it.) the equivalent of setTimeout, with a real zero delay, using postMessage: // Only add setZeroTimeout to the window object, and hide everything // else in a closure. (function() { var timeouts = []; var messageName = "zero-timeout-message"; Like setTimeout, but only takes a function argument. There's no time argument (always zero) and no arguments (you have to use a closure). function setZeroTimeout(fn) { timeouts.push(fn); window.postMessage(messageName, "*"); } function handleMessage(event) { if (event.source == window && event.data == messageName) { event.stopPropagation(); if (timeouts.length > 0) { var fn = timeouts.shift(); fn(); } } } window.addEventListener("message", handleMessage, true); // Add the one thing we want added to the window object. window.setZeroTimeout = setZeroTimeout; })();

    jQuery UI message box

    jQuery UI jqueryui dialog <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <script src="https://code.jquery.com/jquery-1.12.4.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <div id="dialog" title="Basic dialog" style="display:none;"> <p>This is the default dialog which is useful for displaying information. The dialog window can be moved, resized and closed with the 'x' icon.</p> </div> <div id="dialogForm" title="Create new user" style="display:none;"> <p>All form fields are required.</p> <form> <fieldset> <label for="name">Name</label> <input type="text" name="name" id="name" class="text"> <br> <label for="email">Email</label> <input type="text" name="email" id="email" value="" class="text"> <br> <label for="password">Password</label> <input type="password" name="password" id="password" value="" class="text"> </fieldset> </form> </div> <br> <button id="create-user" onclick="$('#dialogForm').toggle()">Create new user</button> <br> <span onclick="$('#dialog').dialog();">click to open dialog</span>

    auto load page with infinite scroll until it gets to the bottom

    var lastScrollHeight = 0; function autoScroll() { var sh = document.documentElement.scrollHeight; if (sh != lastScrollHeight) { lastScrollHeight = sh; document.documentElement.scrollTop = sh; } } window.setInterval(autoScroll, 100); Infinite Scroll jQuery load more data on scroll In jQuery, check whether you have hit the bottom of page using scroll function. Once you hit that, make an ajax call (you can show a loading image here till ajax response) and get the next set of data, append it to the div. This function gets executed as you scroll down the page again. $(window).scroll(function() { if($(window).scrollTop() == $(document).height() - $(window).height()) { // ajax call get data from server and append to the div } }); If you want to load content before reaching 100 pixel of bottom use var loading= false; $(window).scroll(function() { if (!loading && ($(window).scrollTop() > $(document).height() - $(window).height() - 100)) { loading= true; // your content loading call goes here. loading = false; // reset value of loading once content loaded } });

    Stop from copy, disable select

    document.oncontextmenu = new Function("event.returnValue=false"); <body oncontextmenu="return false;"> document.onselectstart = new Function("event.returnValue=false"); document.onselectstart = function() { return false; } document.onselectstart = null; <body onselectstart="return false"> document.getElementById("tmp").onselectstart = function(){return false;}; document.getElementById("tmp").addEventListener("selectstart", function(){return false;}, false); document.getElementById("tmp").attachEvent("onselectstart", function(){return false;});

    three.js

    threejs-fundamentals lessons threejsfundamentals examples Three.js Tutorial, Add 3D Model to WebSite in 5 Minutes Getting Started With Three.js Space Background (Three.js) Warp Portal (Three.js) Build a 3D World in React with Three.js

    gravity

    function distance(x1, y1, x2, y2) { const xDist = x2 - x1 const yDist = y2 - y1 return Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2)) } var canvas = document.querySelector('canvas'); var c = canvas.getContext('2d'); canvas.width = innerWidth; canvas.height = innerHeight; // Variables var mouse = { x: innerWidth / 2, y: innerHeight / 2 }; var colors = ['red','orange','yellow','green','cyan','blue','brown','purple','gold','silver' ]; var gravity = 0.2; var friction = 0.9; // Event Listeners addEventListener("mousemove", function(event) { mouse.x = event.clientX; mouse.y = event.clientY; }); addEventListener("resize", function() { canvas.width = innerWidth; canvas.height = innerHeight; init(); }); addEventListener("click", function(event) { init(); }); // Utility Functions function randomIntFromRange(min,max) { return Math.floor(Math.random() * (max - min + 1) + min); } function randomColor(colors) { return colors[Math.floor(Math.random() * colors.length)]; } // Objects function Ball(x, y, dx, dy, radius, color) { this.x = x; this.y = y; this.dx = dx; this.dy = dy; this.radius = radius; this.color = color; this.update = function() { if (this.y + this.radius + this.dy> canvas.height) { this.dy = -this.dy; this.dy = this.dy * friction; this.dx = this.dx * friction; } else { this.dy += gravity; } if (this.x + this.radius >= canvas.width || this.x - this.radius <= 0) { this.dx = -this.dx * friction; } this.x += this.dx; this.y += this.dy; this.draw(); }; this.draw = function() { c.beginPath(); c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); c.fillStyle = this.color; c.fill(); c.stroke(); c.closePath(); }; } // Implementation var ballArray = []; function init() { ballArray = []; for (let i = 0; i < 1000; i++) { var radius = randomIntFromRange(3, 5); var x = randomIntFromRange(radius, canvas.width - radius); var y = randomIntFromRange(0, canvas.height - radius); var dx = randomIntFromRange(-5, 5) var dy = randomIntFromRange(-2, 2) ballArray.push(new Ball(x, y, dx, dy, radius, randomColor(colors))); } } // Animation Loop function animate() { requestAnimationFrame(animate); c.clearRect(0, 0, canvas.width, canvas.height); for (let i = 0; i < ballArray.length; i++) { ballArray[i].update(); } } init(); animate();

    CSS/Javascript Mouseover Popup Box

    Product 1
    # of Votes: 123
    % Liked
    See User reviews
    loop bind events to all .NameHighlights spans: var span = document.querySelectorAll('.NameHighlights'); for (var i = span.length; i--;) { (function() { var t; span[i].onmouseover = function() { hideAll(); clearTimeout(t); this.className = 'NameHighlightsHover'; }; span[i].onmouseout = function() { var self = this; t = setTimeout(function() { self.className = 'NameHighlights'; }, 300); }; })(); } a jQuery version: var t; $(function(){ $('span.NameHighlights').mouseover( function(e){ hideAll(); clearTimeout(t); $(this).attr('class', 'NameHighlightsHover'); } ).mouseout( function(e){ t = setTimeout(function() { //$(this).attr('class', 'NameHighlights'); hideAll(); }, 300); } ); }); function hideAll() { $('span.NameHighlightsHover').each(function(index) { console.log('insde hideAll'); $(this).attr('class', 'NameHighlights'); }) };

    CORS library

    Learn CORS library In 6 Minutes

    coordinates of the mouse

    coordinates of the mouse pointer when clicked on an element: var x = event.clientX; // Get the horizontal coordinate var y = event.clientY; // Get the vertical coordinate <span onclick="showCoords(event)">get the coordinates when clicked coordinates of the mouse pointer when the mouse is moved: addEventListener("mousemove", function(event) { mouse.x = event.clientX; mouse.y = event.clientY; });

    requestAnimationFrame

    There used to be just one way to do a timed loop in JavaScript: setInterval(). If you needed to repeat something pretty fast (but not as-fast-as-absolutely-possible like a for loop), you’d use that. For the purposes of animation, the goal is sixty “frames” per second to appear smooth, so you’d run a loop like this: setInterval(function() { // animiate something }, 1000/60); There is a better alternative to this now. Paul Irish introduced requestAnimationFrame over two years ago. I don’t have a whole lot to add to it, I just had never actually used it before and now I have so I thought I’d help spread the word and write about its basic usage. Why better? The browser can optimize it, so animations will be smoother Animations in inactive tabs will stop, allowing the CPU to chill More battery-friendly The Simplest Possible Example function repeatOften() { // Do whatever requestAnimationFrame(repeatOften); } requestAnimationFrame(repeatOften); Call it once to kick it off, and your function recursively calls itself. Start and Stop requestAnimationFrame returns an ID you can use to cancel it, just like setTimeout or setInterval does. jQuery used here only to demonstrate a simple animation and bind events. var globalID; function repeatOften() { // repeat loop $("<div />").appendTo("body"); globalID = requestAnimationFrame(repeatOften); } $("#start").on("click", function() { // start button globalID = requestAnimationFrame(repeatOften); }); $("#stop").on("click", function() { // stop button cancelAnimationFrame(globalID); });

    animation of an object along a particular path

    animation of an object along a particular path

    to detect a mobile device

    https://stackoverflow.com/questions/3514784/what-is-the-best-way-to-detect-a-mobile-device /* Smartphones ----------- */ @media only screen and (max-width: 760px) { #some-element { display: none; } } In jQuery/JavaScript file: $( document ).ready(function() { var is_mobile = false; if( $('#some-element').css('display')=='none') { is_mobile = true; } // now I can use is_mobile to run javascript conditionally if (is_mobile == true) { //Conditional script here } }); There is a JavaScript API built-in for detecting media. Rather than using the above solution simply use the following: $(function() { let isMobile = window.matchMedia("only screen and (max-width: 760px)").matches; if (isMobile) { //Conditional script here } }); The screen.width property is a global. If the browser is on a desktop and the user resizes the window, $is_mobile is not going to be updated. Why not: if( screen.width <= 480 ) { // is mobile }

    box2d

    box2d box2d catalog of picked jQuery plugins jquery.box2d box2d html5 canvas box2d

    Test Google Chart

    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <div id="chart" style="width: 900px; height: 500px;"></div> <script> google.charts.load('current', {'packages':['corechart']}); google.charts.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable([ ['Mon', 20, 28, 38, 45], ['Tue', 31, 38, 55, 66], ['Wed', 50, 55, 77, 80], ['Thu', 77, 77, 66, 50], ['Fri', 68, 66, 22, 15] // Treat first row as data as well. ], true); var options = {legend:'none'}; var chart = new google.visualization.CandlestickChart(document.getElementById('chart')); chart.draw(data, options); } </script>

    check if variable exists (is defined/initialized)

    if (typeof variable !== 'undefined') { // the variable is defined }

    Game

    franksLaboratory JavaScript Game Tutorial - 2D Tower Defense JavaScript Game Tutorial - 2D Tower Defense PART 2 DOWNLOAD: Flappy Bird In JAVASCRIPT SOURCE CODE

    To display a sprite

    Set up HTML


    Programming_Sprites_in_JavaScript build a simple sprite animation in JavaScript Set up your HTML file: Create an HTML file and include a <canvas> element where you want to display the sprite. Give the canvas an id attribute to reference it in JavaScript. <!DOCTYPE html> <html> <head> <title>Sprite Display</title> <style> canvas { border: 1px solid black; } </style> </head> <body> <canvas id="myCanvas" width="800" height="600"></canvas> <script src="script.js"></script> </body> </html> Create your sprite image: Prepare an image file that represents your sprite. You can use an existing image or create your own. Save the image file in the same directory as your HTML file.

    JavaScript code


    Write JavaScript code: Create a JavaScript file (e.g., script.js) and link it to your HTML file. In the JavaScript file, you will load the sprite image and draw it on the canvas. // Get the canvas element const canvas = document.getElementById("myCanvas"); const ctx = canvas.getContext("2d"); // Load the sprite image const spriteImg = new Image(); spriteImg.src = "sprite.png"; // Draw the sprite on the canvas spriteImg.onload = function() { ctx.drawImage(spriteImg, 0, 0); }; Run your code: Open the HTML file in a web browser, and you should see the sprite displayed on the canvas. Make sure to replace "sprite.png" with the actual filename and extension of your sprite image. Adjust the canvas dimensions (width and height) to match your desired size. This basic example assumes that your sprite image is a single frame. If you have a sprite sheet with multiple frames, you'll need additional logic to animate the sprite by updating the image source or manipulating the drawImage parameters.

    To animate a sprite


    To animate a sprite and create movement or interactivity, you can use JavaScript's requestAnimationFrame method along with the drawImage function. // Get the canvas element const canvas = document.getElementById("myCanvas"); const ctx = canvas.getContext("2d"); // Load the sprite image const spriteImg = new Image(); spriteImg.src = "sprite.png"; // Sprite position and velocity let spriteX = 0; let spriteY = 0; let spriteSpeed = 2; // Update sprite position function updateSprite() { // Clear the canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw the sprite on the canvas ctx.drawImage(spriteImg, spriteX, spriteY); // Update sprite position spriteX += spriteSpeed; // Wrap the sprite around the canvas if (spriteX > canvas.width) { spriteX = -spriteImg.width; } // Request the next animation frame requestAnimationFrame(updateSprite); } // Start the animation spriteImg.onload = function() { updateSprite(); }; In this example, we define the initial position of the sprite (spriteX and spriteY) and the speed at which it moves (spriteSpeed). The updateSprite function is called repeatedly using requestAnimationFrame, which ensures smooth animation by syncing with the browser's refresh rate. Inside the updateSprite function, we clear the canvas, draw the sprite at its current position using drawImage, update the sprite's position, and wrap it around the canvas if it goes beyond the canvas width. You can modify the updateSprite function to add interactivity, such as responding to keyboard or mouse events to control the sprite's movement. Additionally, you can use different frames from a sprite sheet to create animated sequences by adjusting the drawImage parameters. Remember to replace "sprite.png" with the actual filename and extension of your sprite image.

    different techniques and effects


    Here are a few examples of sprite animations using different techniques and effects:

    1. Sprite Sheet Animation


    : This technique involves using a sprite sheet that contains multiple frames of the animation. By updating the position of the sprite sheet and specifying the frame dimensions, you can create an animated sequence. javascript: // Get the canvas element const canvas = document.getElementById("myCanvas"); const ctx = canvas.getContext("2d"); // Load the sprite sheet image const spriteSheet = new Image(); spriteSheet.src = "spritesheet.png"; // Sprite sheet properties const frameWidth = 64; const frameHeight = 64; const totalFrames = 8; // Current frame index let currentFrame = 0; // Update sprite sheet position and draw the current frame function updateSpriteSheet() { // Clear the canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw the current frame of the sprite sheet ctx.drawImage( spriteSheet, currentFrame * frameWidth, 0, frameWidth, frameHeight, 0, 0, frameWidth, frameHeight ); // Increment the frame index currentFrame = (currentFrame + 1) % totalFrames; // Request the next animation frame requestAnimationFrame(updateSpriteSheet); } // Start the animation spriteSheet.onload = function() { updateSpriteSheet(); }; ```

    2. Sprite Scaling and Rotation


    : You can apply scaling and rotation transformations to the sprite to create effects like resizing or spinning. javascript: // Get the canvas element const canvas = document.getElementById("myCanvas"); const ctx = canvas.getContext("2d"); // Load the sprite image const spriteImg = new Image(); spriteImg.src = "sprite.png"; // Sprite position and properties let spriteX = 200; let spriteY = 200; let spriteWidth = 100; let spriteHeight = 100; let rotationAngle = 0; // Update sprite properties and draw it function updateSprite() { // Clear the canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Apply transformations to the sprite ctx.save(); ctx.translate(spriteX, spriteY); ctx.rotate((rotationAngle * Math.PI) / 180); ctx.drawImage(spriteImg, -spriteWidth / 2, -spriteHeight / 2, spriteWidth, spriteHeight); ctx.restore(); // Update sprite properties spriteWidth += 1; spriteHeight += 1; rotationAngle += 1; // Request the next animation frame requestAnimationFrame(updateSprite); } // Start the animation spriteImg.onload = function() { updateSprite(); }; ```

    3. Particle Effect using Sprites


    : You can create a particle effect by animating multiple sprites that represent particles. Each particle can have its own position, velocity, and lifespan. javascript: // Get the canvas element const canvas = document.getElementById("myCanvas"); const ctx = canvas.getContext("2d"); // Load the particle sprite image const particleImg = new Image(); particleImg.src = "particle.png"; // Particle class class Particle { constructor(x, y, vx, vy) { this.x = x; this.y = y; this.vx = vx; this.vy = vy; this.lifespan = 100; } update() { // Update particle position this.x += this.vx; this.y += this.vy; // Reduce particle lifespan this.lifespan--; // Draw the particle ctx.drawImage(particleImg, this.x, this.y); return this.lifespan > 0; } } // Create an array of particles const particles = []; // Animation loop function animateParticles() { // Clear the canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Update and draw particles for (let i = 0; i < particles.length; i++) { const particle = particles[i]; if (particle.update()) { // Particle is still alive, keep it particles[i] = particle; } else { // Particle has expired, remove it particles.splice(i, 1); i--; } } // Create new particles if (Math.random() < 0.1) { const x = Math.random() * canvas.width; const y = Math.random() * canvas.height; const vx = (Math.random() - 0.5) * 2; const vy =Apologies for the incomplete response.

    complete example


    Here's the complete example for the particle effect using sprites: javascript: // Get the canvas element const canvas = document.getElementById("myCanvas"); const ctx = canvas.getContext("2d"); // Load the particle sprite image const particleImg = new Image(); particleImg.src = "particle.png"; // Particle class class Particle { constructor(x, y, vx, vy) { this.x = x; this.y = y; this.vx = vx; this.vy = vy; this.lifespan = 100; } update() { // Update particle position this.x += this.vx; this.y += this.vy; // Reduce particle lifespan this.lifespan--; // Draw the particle ctx.drawImage(particleImg, this.x, this.y); return this.lifespan > 0; } } // Create an array of particles const particles = []; // Animation loop function animateParticles() { // Clear the canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Update and draw particles for (let i = 0; i < particles.length; i++) { const particle = particles[i]; if (particle.update()) { // Particle is still alive, keep it particles[i] = particle; } else { // Particle has expired, remove it particles.splice(i, 1); i--; } } // Create new particles if (Math.random() < 0.1) { const x = Math.random() * canvas.width; const y = Math.random() * canvas.height; const vx = (Math.random() - 0.5) * 2; const vy = (Math.random() - 0.5) * 2; particles.push(new Particle(x, y, vx, vy)); } // Request the next animation frame requestAnimationFrame(animateParticles); } // Start the animation particleImg.onload = function() { animateParticles(); }; In this example, we create a Particle class representing each particle in the particle effect. The Particle class has properties for position (x and y), velocity (vx and vy), and lifespan. The update method is responsible for updating the particle's position, reducing its lifespan, and drawing it on the canvas. In the animateParticles function, we clear the canvas, update and draw each particle, remove expired particles from the array, and create new particles randomly. The animation loop continues by recursively calling requestAnimationFrame. Make sure to replace "particle.png" with the actual filename and extension of your particle sprite image. Feel free to customize the particle effect by adjusting the particle properties or modifying the creation logic.

    sprites in games

    explain sprites in games Sprite sheets packer TexturePacker Sprite sheets and game graphics Download the Free Game Graphics game graphics

    Set Objects

    A Set is a collection of unique values. Each value may occur only once in a Set. A Set can hold any values of any data type. // Create a Set const letters = new Set(); // Add some values to the Set letters.add("a"); letters.add("b"); letters.add("c"); // Create a new Set const letters = new Set(["a","b","c"]); For a Set, typeof returns object: typeof letters; // Returns object For a Set, instanceof Set returns true: letters instanceof Set; // Returns true Add equal elements to set, only the first will be saved: letters.add("a"); letters.add("b"); letters.add("c"); letters.add("c"); letters.size; // 3 Set Object Methods and Properties new Set() Creates a new Set object add() Adds a new element to the Set clear() Removes all elements from a Set delete() Removes an element specified by its value. entries() Returns an array of the values in a Set object has() Returns true if a value exists forEach() Invokes a callback for each element keys() Returns an array of the values in a Set object values() Same as keys() size Returns the element count

    Map and set

    https://www.digitalocean.com/community/tutorials/understanding-map-and-set-objects-in-javascript Map is a collection of keyed data items, just like an Object. But the main difference is that Map allows keys of any type. Methods and properties are: new Map() – creates the map. map.set(key, value) – stores the value by the key. map.get(key) – returns the value by the key, undefined if key doesn’t exist in map. map.has(key) – returns true if the key exists, false otherwise. map.delete(key) – removes the value by the key. map.clear() – removes everything from the map. map.size – returns the current element count. For instance: let map = new Map(); map.set('1', 'str1'); // a string key map.set(1, 'num1'); // a numeric key map.set(true, 'bool1'); // a boolean key map.set('firstName', 'Luke') map.set('lastName', 'Skywalker') map.set('occupation', 'Jedi Knight') recreate the same Map const map = new Map([ ['firstName', 'Luke'], ['lastName', 'Skywalker'], ['occupation', 'Jedi Knight'], ]) // remember the regular Object? it would convert keys to string // Map keeps the type, so these two are different: alert( map.get(1) ); // 'num1' alert( map.get('1') ); // 'str1' alert( map.size ); // 3 Map can also use objects as keys. For instance: let john = { name: "John" }; // for every user, let's store their visits count let visitsCountMap = new Map(); // john is the key for the map visitsCountMap.set(john, 123); alert( visitsCountMap.get(john) ); // 123 We can initialize a new Map to demonstrate the following methods and properties: delete(), has(), get(), and size. // Initialize a new Map const map = new Map([ ['animal', 'otter'], ['shape', 'triangle'], ['city', 'New York'], ['country', 'Bulgaria'], ]) // Check if a key exists in a Map map.has('shark') // false map.has('country') // true // Get an item from a Map map.get('animal') // "otter" // Get the count of items in a Map map.size // 4 // Delete an item from a Map by key map.delete('city') // true // Empty a Map map.clear() The keys(), values(), and entries() methods all return a MapIterator, which is similar to an Array in that you can use for...of to loop through the values. const map = new Map([ [1970, 'bell bottoms'], [1980, 'leg warmers'], [1990, 'flannel'], ]) The keys() method returns the keys: map.keys() The values() method returns the values: map.values() The entries() method returns an array of key/value pairs: map.entries() Map has a built-in forEach method, similar to an Array, for built-in iteration. However, there is a bit of a difference in what they iterate over. The callback of a Map’s forEach iterates through the value, key, and map itself, while the Array version iterates through the item, index, and array itself. // Map Map.prototype.forEach((value, key, map) = () => {}) // Array Array.prototype.forEach((item, index, array) = () => {}) Map Properties and Methods Properties/Methods Description Returns set(key, value) Appends a key/value pair to a Map Map Object delete(key) Removes a key/value pair from a Map by key Boolean get(key) Returns a value by key value has(key) Checks for the presence of an element in a Map by key Boolean clear() Removes all items from a Map N/A keys() Returns all keys in a Map MapIterator object values() Returns all values in a Map MapIterator object entries() Returns all keys and values in a Map as [key, value] MapIterator object forEach() Iterates through the Map in insertion order N/A size Returns the number of items in a Map Number When to Use Map Summing up, Maps are similar to Objects in that they hold key/value pairs, but Maps have several advantages over objects: Size - Maps have a size property, whereas Objects do not have a built-in way to retrieve their size. Iteration - Maps are directly iterable, whereas Objects are not. Flexibility - Maps can have any data type (primitive or Object) as the key to a value, while Objects can only have strings. Ordered - Maps retain their insertion order, whereas objects do not have a guaranteed order. Due to these factors, Maps are a powerful data structure to consider. However, Objects haves some important advantages as well: JSON - Objects work flawlessly with JSON.parse() and JSON.stringify(), two essential functions for working with JSON, a common data format that many REST APIs deal with. Working with a single element - Working with a known value in an Object, you can access it directly with the key without the need to use a method, such as Map’s get(). This list will help you decide if a Map or Object is the right data structure for your use case.

    dat.gui

    We all love trusted JavaScript frameworks like MooTools, jQuery, and Dojo, but there's a big push toward using focused micro-frameworks for smaller purposes. dat.gui's niche is in listening to and controlling data such that it can be visualized into charts or other graphics. Creating a new DAT.GUI instance provides a new sliding pane for which to add controls to: // Create an instance, which also creates a UI pane var gui = new DAT.GUI(); With the pane ready, new controls can be added. Fields can be of type string, number, boolean, or function, with a number slider available depending on options passed to it. Here's how you can create a field of each type: // My sample abject var obj = { name: "David Walsh", num: 23, winner: true }; // String field gui.add(obj, "name"); // Number field with slider gui.add(obj, "num").min(1).max(50).step(1); // Checkbox field gui.add(obj, "winner"); Since properties are changed directly on the object itself, there's not "setter" and so dat.gui provides a listen function to do just that -- list for changes: // Listen to changes within the GUI gui.add(obj, "name").onChange(function(newValue) {console.log("Value changed to: ", newValue); }); // Listen to changes outside the GUI - GUI will update when changed from outside gui.add(obj, "name").listen(); Those are the dead basics of the dat.gui library. Note that I've not yet mentioned what the result looks like. That's because it's up to you to create the visual aspects based on property values. The demo that ships with dat.gui is a very creative dot-based constant animation. The animation magic lies within the FizzyText function. FizzyText is a more sizable function that does the animation, but let's take a look at the dat.gui code: var fizzyText = new FizzyText("david walsh"); var gui = new DAT.GUI(); // Text field gui.add(fizzyText, "message"); // Sliders with min + max gui.add(fizzyText, "maxSize").min(0.5).max(7); gui.add(fizzyText, "growthSpeed").min(0.01).max(1).step(0.05); gui.add(fizzyText, "speed", 0.1, 2, 0.05); // shorthand for min/max/step // Sliders with min, max and increment. gui.add(fizzyText, "noiseStrength", 10, 100, 5); // Boolean checkbox gui.add(fizzyText, "displayOutline"); Tinker with the pane fields and the animation instantly changes! JavaScript, more than any other language, seems to provide the most ability to make powerful changes with very little code. dat.gui is proof of that. The demo provided here is the same demo provided within the dat.gui repository, mostly because topping the effect would be a hell of a feat. When you get a few moments, go play around with dat.gui -- it's really ... dat ... good. </script> // Define your database var db = new Dexie("friend_database"); db.version(1).stores({ friends: 'name,shoeSize' }); // Put some data into it db.friends.put({name: "Nicolas", shoeSize: 8}).then (function(){ // Then when data is stored, read from it return db.friends.get('Nicolas'); }).then(function(friend) { // Display the result alert ("Nicolas has shoe size " + friend.shoeSize); }).catch(function(error) { // Finally don't forget to catch any error // that could have happened anywhere in the // code blocks above. alert ("Ooops: " + error); });

    Dexie.js Minimalistic IndexedDB Wrapper

    Dexie.js Dexie.js guide

    access camera


    Introduction

    With HTML5 came the introduction of APIs with access to device hardware, including the MediaDevices API. This API provides access to media input devices like audio and video. With this API's help, developers can access audio and video devices to stream and display live video feeds in the browser. In this tutorial, you'll access the video feed from the user's device and display it in the browser using the method. The getUserMedia API makes use of the media input devices to produce a MediaStream. This MediaStream contains the requested media types, whether audio or video. Using the stream returned from the API, video feeds can be displayed on the browser, which is useful for real-time communication on the browser. When used along with the MediaStream Recording API, you can record and store media data captured on the browser. This API only works on secure origins like the rest of the newly introduced APIs, but it also works on localhost and file URLs.

    Prerequisites

    A basic knowledge of JavaScript. If you are new to JavaScript, try checking out the How To Code in JavaScript series. This tutorial will first explain concepts and demonstrate examples with Codepen. In the final step, you will create a functioning video feed for the browser.

    Step 1 — Checking Device Support

    First, you will see how to check if the user's browser supports the mediaDevices API. This API exists within the navigator interface and contains the current state and identity of the user agent. The check is performed with the following code that can be pasted into Codepen: if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) { console.log("Let's get this party started") } First, this checks if the mediaDevices API exists within the navigator and then checks if the getUserMedia API is available within the mediaDevices. If this returns true, you can get started.

    Step 2 — Requesting User Permission

    After confirming the browser's support for getUserMedia, you need to request permission to make use of the media input devices on the user agent. Typically, after a user grants permission, a Promise is returned which resolves to a media stream. This Promise isn't returned when the permission is denied by the user, which blocks access to these devices. Paste the following line into Codepen to request permission: navigator.mediaDevices.getUserMedia({video: true}) The object provided as an argument for the getUserMedia method is called constraints. This determines which of the media input devices you are requesting permissions to access. For example, if the object contains audio: true, the user will be asked to grant access to the audio input device.

    Step 3 — Understanding Media Constraints

    This section will cover the general concept of contraints. The constraints object is a object that specifies the types of media to request and the requirements of each media type. You can specify requirements for the requested stream using the constraints object, like the resolution of the stream to use (front, back). You must specify either audio or video when making the request. A NotFoundError will be returned if the requested media types can't be found on the user's browser. If you intend to request a video stream of 1280 x 720 resolution, you can update the constraints object to look like this: { video: { width: 1280, height: 720, } } With this update, the browser will try to match the specified quality settings for the stream. If the video device can't deliver this resolution, the browser will return other available resolutions. To ensure that the browser returns a resolution not lower than the one provided you will have to make use of the min property. Here is how you could update the constraints object to include the min property: { video: { width: { min: 1280, }, height: { min: 720, } } } This will ensure that the stream resolution returned will be at least 1280 x 720. If this minimum requirement can't be met, the promise will be rejected with an OverconstrainedError. In some cases you may be concerned about saving data and need the stream to not exceed a set resolution. This can come in handy when the user is on a limited plan. To enable this functionality, update the constraints object to contain a max field: { video: { width: { min: 1280, max: 1920, }, height: { min: 720, max: 1080 } } } With these settings, the browser will ensure that the return stream doesn't go below 1280 x 720 and doesn't exceed 1920 x 1080. Other terms that can be used includes exact and ideal. The ideal setting is typically used along with the min and max properties to find the best possible setting closest to the ideal values provided. You can update the constraints to use the ideal keyword: { video: { width: { min: 1280, ideal: 1920, max: 2560, }, height: { min: 720, ideal: 1080, max: 1440 } } } To tell the browser to make use of the front or back (on mobile) camera on devices, you can specify a facingMode property in the video object: { video: { width: { min: 1280, ideal: 1920, max: 2560, }, height: { min: 720, ideal: 1080, max: 1440 }, facingMode: 'user' } } This setting will make use of the front-facing camera at all times in all devices. To make use of the back camera on mobile devices, you can alter the facingMode property to environment. { video: { ... facingMode: { exact: 'environment' } } }

    Step 4 — Using the enumerateDevices Method

    When the enumerateDevices method is called, it returns all of the available input media devices available on the user's PC. With the method, you can provide the user options on which input media device to use for streaming audio or video content. This method returns a Promise resolved to a MediaDeviceInfo array containing information about each device. An example of how to make a use of this method is shown in the snippet below: async function getDevices() { const devices = await navigator.mediaDevices.enumerateDevices(); } A sample response for each of the devices would look like the following: { deviceId: "23e77f76e308d9b56cad920fe36883f30239491b8952ae36603c650fd5d8fbgj", groupId: "e0be8445bd846722962662d91c9eb04ia624aa42c2ca7c8e876187d1db3a3875", kind: "audiooutput", label: "", } Note: A label won't be returned unless an available stream is available, or if the user has granted device access permissions.

    Step 5 — Displaying the Video Stream on the Browser

    You have gone through the process of requesting and getting access to the media devices, configured constraints to include required resolutions, and selected the camera you will need to record video. After going through all these steps, you'll at least want to see if the stream is delivering based on the configured settings. To ensure this, you will make use of the <video> element to display the video stream on the browser. Like mentioned earlier, the getUserMedia method returns a Promise that can be resolved to a stream. The returned stream can be converted to an object URL using the method. This URL will be set as a video source. You will create a short demo where we let the user choose from their available list of video devices. using the method. This is a navigator.mediaDevices method. It lists the available media devices, such as microphones and cameras. It returns a Promise resolvable to an array of objects detailing the available media devices. Create an index.html file and update the contents with the code below:
    index.html
    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"> <link rel="stylesheet" href="style.css"> <title>Document</title> </head> <body> <div> <video autoplay></video> <canvas></canvas> <div> <select name=""> <option value="">Select camera</option> </select> </div> <img> <div> <button title="Play"><i data-feather="play-circle"></i></button> <button title="Pause"><i data-feather="pause"></i></button> <button title="ScreenShot"><i data-feather="image"></i></button> </div> </div> <script src="https://unpkg.com/feather-icons"></script> <script src="script.js"></script>gt; </body> </html> In the snippet above, you have set up the elements you will need and a couple of controls for the video. Also included is a button for taking screenshots of the current video feed. Now, let's style up these components a bit. Create a style.css file and copy the following styles into it. Bootstrap was included to reduce the amount of CSS you will need to write to get the components going.
    style.css
    .screenshot-image { width: 150px; height: 90px; border-radius: 4px; border: 2px solid whitesmoke; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1); position: absolute; bottom: 5px; left: 10px; background: white; } .display-cover { display: flex; justify-content: center; align-items: center; width: 70%; margin: 5% auto; position: relative; } video { width: 100%; background: rgba(0, 0, 0, 0.2); } .video-options { position: absolute; left: 20px; top: 30px; } .controls { position: absolute; right: 20px; top: 20px; display: flex; } .controls > button { width: 45px; height: 45px; text-align: center; border-radius: 100%; margin: 0 6px; background: transparent; } .controls > button:hover svg { color: white !important; } @media (min-width: 300px) and (max-width: 400px) { .controls { flex-direction: column; } .controls button { margin: 5px 0 !important; } } .controls > button > svg { height: 20px; width: 18px; text-align: center; margin: 0 auto; padding: 0; } .controls button:nth-child(1) { border: 2px solid #D2002E; } .controls button:nth-child(1) svg { color: #D2002E; } .controls button:nth-child(2) { border: 2px solid #008496; } .controls button:nth-child(2) svg { color: #008496; } .controls button:nth-child(3) { border: 2px solid #00B541; } .controls button:nth-child(3) svg { color: #00B541; } .controls > button { width: 45px; height: 45px; text-align: center; border-radius: 100%; margin: 0 6px; background: transparent; } .controls > button:hover svg { color: white; } The next step is to add functionality to the demo. Using the enumerateDevices method, you will get the available video devices and set it as the options within the select element. Create a file called script.js and update it with the following snippet:
    script.js
    feather.replace(); const controls = document.querySelector('.controls'); const cameraOptions = document.querySelector('.video-options>select'); const video = document.querySelector('video'); const canvas = document.querySelector('canvas'); const screenshotImage = document.querySelector('img'); const buttons = [...controls.querySelectorAll('button')]; let streamStarted = false; const [play, pause, screenshot] = buttons; const constraints = { video: { width: { min: 1280, ideal: 1920, max: 2560, }, height: { min: 720, ideal: 1080, max: 1440 }, } }; const getCameraSelection = async () => { const devices = await navigator.mediaDevices.enumerateDevices(); const videoDevices = devices.filter(device => device.kind === 'videoinput'); const options = videoDevices.map(videoDevice => { return `<option value="${videoDevice.deviceId}">${videoDevice.label}</option>`; }); cameraOptions.innerHTML = options.join(''); }; play.onclick = () => { if (streamStarted) { video.play(); play.classList.add('d-none'); pause.classList.remove('d-none'); return; } if ('mediaDevices' in navigator && navigator.mediaDevices.getUserMedia) { const updatedConstraints = { ...constraints, deviceId: { exact: cameraOptions.value } }; startStream(updatedConstraints); } }; const startStream = async (constraints) => { const stream = await navigator.mediaDevices.getUserMedia(constraints); handleStream(stream); }; const handleStream = (stream) => { video.srcObject = stream; play.classList.add('d-none'); pause.classList.remove('d-none'); screenshot.classList.remove('d-none'); streamStarted = true; }; getCameraSelection(); In the snippet above, there are a couple of things going on. Let's break them down:
      feather.replace(): this method call instantiates feather, which is an icon set for web development. The constraints variable holds the initial configuration for the stream. This will be extended to include the media device the user chooses. getCameraSelection: this function calls the enumerateDevices method. Then, you filter through the array from the resolved Promise and select video input devices. From the filtered results, you create <option> for the <select> element. Calling the getUserMedia method happens within the onclick listener of the play button. Here, you will check if this method is supported by the user's browser before starting the stream. Next, you will call the startStream function that takes a constraints argument. It calls the getUserMedia method with the provided constraints. handleStream is called using the stream from the resolved Promise. This method sets the returned stream to the video element's srcObject.
    Next, you will add click listeners to the button controls on the page to pause, stop, and take screenshots. Also, you will add a listener to the <select> element to update the stream constraints with the selected video device. Update the script.js file with the code below:
    script.js
    ... cameraOptions.onchange = () => { const updatedConstraints = { ...constraints, deviceId: { exact: cameraOptions.value } }; startStream(updatedConstraints); }; const pauseStream = () => { video.pause(); play.classList.remove('d-none'); pause.classList.add('d-none'); }; const doScreenshot = () => { canvas.width = video.videoWidth; canvas.height = video.videoHeight; canvas.getContext('2d').drawImage(video, 0, 0); screenshotImage.src = canvas.toDataURL('image/webp'); screenshotImage.classList.remove('d-none'); }; pause.onclick = pauseStream; screenshot.onclick = doScreenshot; Now, when you open the index.html file in the browser, clicking the Play button will start the stream. Here is a complete demo: https://codepen.io/chrisbeast/pen/ebYwpX

    Conclusion

    This tutorial introduced the getUserMedia API. It is an interesting addition to HTML5 that eases the process of capturing media on the web. The API takes a parameter (constraints) that can be used to configure the access to audio and video input devices. It can also be used to specify the video resolution required for your application. You can extend the demo further to give the user an option to save the screenshots taken, as well as recording and storing video and audio data with the help of MediaStream Recording API. https://stackoverflow.com/questions/12024770/access-camera-from-a-browser

    Web Audio

    p5.sound Web Audio including audio input, playback, analysis and synthesis p5.sound getLevel

    IOT and robotic

    Javascript iot-libraries (robotics) On-Robot JavaScript API Tutorials

    jquery set img width and height

    $('img').css('max-height', $(window).height()); $("img").click(function() { $('img').css('max-height', $(window).height()); window.location = "#topic-" + topicpointer; }) $("img").dblclick(function() { $('img').css('max-height', '100%'); window.location = "#topic-" + topicpointer; }) img{max-height:100vh;} img{max-width:100vh;}

    popup was blocked

    to test if a popup was blocked and take action in case. function pop(url,w,h) { n=window.open(url,'_blank','toolbar=0,location=0,directories=0,status=1,menubar=0,titlebar=0,scrollbars=1,resizable=1,width='+w+',height='+h); if(n==null) { alert("popup blocked") return true; } return false; }

    write to page

    var html=""; html +='<div class="main clearFix inner new-center2">'; document.write(html);

    Make anchor link go some pixels above

    window.addEventListener("hashchange", function() { window.scrollTo(window.scrollX, window.scrollY - 20); }); Make anchor link go some pixels above where it's linked to Make an Anchor Link Go Some Pixels Above Where it’s Linked To

    software Open Source Projects

    interesting Open Source projects Fuse.js is a fuzzy-search library JavaScript keyword highlighter Prism is a syntax highlighter An animated loader graphic module.

    AJAX Database Example

    The following example will demonstrate how a web page can fetch information from a database with AJAX <h2>The XMLHttpRequest Object</h2> <form action=""> <select name="customers" onchange="showCustomer(this.value)"> <option value="">Select a customer:</option> <option value="ALFKI">Alfreds Futterkiste</option> <option value="NORTS ">North/South</option> <option value="WOLZA">Wolski Zajazd</option> </select> </form> <br> <div id="txtHint">Customer info will be listed here...</div> <script> function showCustomer(str) { if (str == "") { document.getElementById("txtHint").innerHTML = ""; return; } const xhttp = new XMLHttpRequest(); xhttp.onload = function() { document.getElementById("txtHint").innerHTML = this.responseText; } xhttp.open("GET", "getcustomer.php?q="+str); xhttp.send(); } The showCustomer() Function When a user selects a customer in the dropdown list, a function called showCustomer() is executed. The function is triggered by the onchange event: showCustomer function showCustomer(str) { if (str == "") { document.getElementById("txtHint").innerHTML = ""; return; } const xhttp = new XMLHttpRequest(); xhttp.onload = function() { document.getElementById("txtHint").innerHTML = this.responseText; } xhttp.open("GET", "getcustomer.php?q="+str); xhttp.send(); } The showCustomer() function does the following: Check if a customer is selected Create an XMLHttpRequest object Create the function to be executed when the server response is ready Send the request off to a file on the server Notice that a parameter (q) is added to the URL (with the content of the dropdown list) The AJAX Server Page The page on the server called by the JavaScript above is a PHP file called "getcustomer.php". The source code in "getcustomer.php" runs a query against a database, and returns the result in an HTML table: <?php $mysqli = new mysqli("servername", "username", "password", "dbname"); if($mysqli->connect_error) { exit('Could not connect'); } $sql = "SELECT customerid, companyname, contactname, address, city, postalcode, country FROM customers WHERE customerid = ?"; $stmt = $mysqli->prepare($sql); $stmt->bind_param("s", $_GET['q']); $stmt->execute(); $stmt->store_result(); $stmt->bind_result($cid, $cname, $name, $adr, $city, $pcode, $country); $stmt->fetch(); $stmt->close(); echo "<table>"; echo "<tr>"; echo "<th>CustomerID</th>"; echo "<td>" . $cid . "</td>"; echo "<th>CompanyName</th>"; echo "<td>" . $cname . "</td>"; echo "<th>ContactName</th>"; echo "<td>" . $name . "</td>"; echo "<th>Address</th>"; echo "<td>" . $adr . "</td>"; echo "<th>City</th>"; echo "<td>" . $city . "</td>"; echo "<th>PostalCode</th>"; echo "<td>" . $pcode . "</td>"; echo "<th>Country</th>"; echo "<td>" . $country . "</td>"; echo "</tr>"; echo "</table>"; ?>

    online compiler

    javascript compiler javascript online compiler tutorialspoint online_javascript_editor playcode javascript online replit online compiler

    execute script code in a javascript append

    appending HTML into the DOM does not cause the browser to evaluate any script tags in said appended HTML. If you really wanted to, you could evaluate the javascript by using eval(): eval($(this).find("script").text()); I know this is an old question but I've had a similar problem today. The solution was using createContextualFragment. My code looks something like this: var tagString = '<script async type="text/javascript" src="path_to_script"></script>'; var range = document.createRange(); range.selectNode(document.getElementsByTagName("BODY")[0]); var documentFragment = range.createContextualFragment(tagString); document.body.appendChild(documentFragment); This code works in my browser. $('body').append('<script>alert("test");<' + '/' + 'script>'); so it might be that $(this) is what is actually causing your problem. Can you replace it with 'body' and see if it works like that?

    after append

    jquery insert after $( "<p>Test</p>" ).insertAfter( ".inner" ); jquery append after <div class="container"> <h2>Greetings</h2> <div class="inner">Hello</div> <div class="inner">Goodbye</div> </div> <script>$( "<p>Test</p>" ).insertAfter( ".inner" );</script> append after div .after() puts the element after the element using after: $('.a').after($('.c')); after execution: <div class='a'> <div class='b'>b</div> </div> <div class='c'>c</div> //<----this will be placed here

    Run script after appending it to the HTML

    jQuery provides the $.getScript(url [,success]) function. You can then load and execute your code from a separate jquery file which helps to manage and control the flow of execution. basically put your alert("testing!") script inside a separate file, for instance alert.js in the same directory. Then you can run the script when adding your employee to the HTML. var str = '

    Examplee

    '; var url = 'alert.js'; document.body.innerHTML += str; $.getScript(url); I know this may seem like more work, but it is better practice to keep your javascript out of your HTML. You can also use a callback to gather user data after the alert or notify another process that the user has been alerted. $.getScript(url, function(){ //do something after the alert is executed. }); For instance maybe it would be a better design to add the employee after the alert is executed. var str = '

    Examplee

    '; var url = 'alert.js'; $.getScript(url, function(){ document.body.innerHTML += str; }); Edit: I know jQuery is not tagged, but I am also no petitioning to be the accepted answer to this question. I am only offering another alternative for someone who may run into the same issue and may be using jQuery. If that is the case $.getScript is a very useful tool designed for this exact problem.

    Failed to load resource

    net::ERR_BLOCKED_BY_CLIENT with Google chrome These errors are usually generated from an ad blocking plugin, such as Adblock Plus. To test this use either a different browser or uninstall the ad blocking plugin. There is an easier way to temporarily disable an extension. In Chrome, opening an Incognito tab will usually stop extensions running. use ctrl+shift+N

    Count frequency

    var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4] arr.reduce(function(acc, item) { return acc[item] ? ++acc[item] : acc[item] = 1, acc }, {}); console.log(arr) // => {2: 5, 4: 1, 5: 3, 9: 1} or arr.reduce((acc, item) => { acc[item] = (acc[item] || 0) + 1 return acc }, {}) to create an incremental range, pre sort the array arr.sort(); to apply a filter within range var res = arr.filter(function(item) { return item <= range.max && item >= range.min; }); arr.filter(function(item) { return item <= 5 && item >= 3; }); loop to find frequency distribution by bins By default, the sort method sorts elements alphabetically. To sort numerically just add a new method which handles numeric sorts arr.sort(function(a, b) { return a - b; }) // note the minus operation var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4, 3,6,6,8,7,1,2,4, 4,2,7,5,10,11,12] arr.map(x => parseInt(x)) // arr.sort() arr.sort(function(a, b) { return a - b; }) // note the minus operation bins = 4 theMin = Math.min( ...arr ) theMax = Math.max( ...arr ) range = theMax - theMin interval = range / bins freq = [] for (i = theMin; i <= theMax; i += interval) { if(i + interval == theMax){ var selected = arr.filter(function(item) { return item >= i && item <= i + interval; }); }else{ var selected = arr.filter(function(item) { return item >= i && item < i + interval; }); } counts = selected.length console.log(i, " selected ",selected, " counts ",counts) freq.push(counts) } freq.pop() // the last one is not intended

    find Mode, mean, std, variance

    function findMode(arr) { var modes = [], count = [], i, number, maxIndex = 0; for (i = 0; i < arr.length; i += 1) { number = arr[i]; count[number] = (count[number] || 0) + 1; if (count[number] > maxIndex) { maxIndex = count[number]; } } for (i in count) if (count.hasOwnProperty(i)) { if (count[i] === maxIndex) { modes.push(Number(i)); } } return modes; } interquartile range standard deviation Cumulative Frequency Distributions // sort array ascending const asc = arr => arr.sort((a, b) => a - b); const sum = arr => arr.reduce((a, b) => a + b, 0); const mean = arr => sum(arr) / arr.length; // sample standard deviation const std = (arr) => { const mu = mean(arr); const diffArr = arr.map(a => (a - mu) ** 2); return Math.sqrt(sum(diffArr) / (arr.length - 1)); }; const quantile = (arr, q) => { const sorted = asc(arr); const pos = (sorted.length - 1) * q; const base = Math.floor(pos); const rest = pos - base; if (sorted[base + 1] !== undefined) { return sorted[base] + rest * (sorted[base + 1] - sorted[base]); } else { return sorted[base]; } }; const findVariance = (array = []) => { if(!array.length){ return 0; }; const sum = array.reduce((acc, val) => acc + val); const { length: num } = array; const median = sum / num; let variance = 0; array.forEach(num => { variance += ((num - median) * (num - median)); }); variance /= num; return variance; }; const q25 = arr => quantile(arr, .25); const q50 = arr => quantile(arr, .50); const q75 = arr => quantile(arr, .75); const median = arr => q50(arr); to find q25 of an numArray q25(numArray)

    To check max input length by prompt

    var rep = "+" ; while (rep != null) { document.write(rep.length + " " + rep + "<br>") ; rep = prompt("Input length was : " + rep.length, rep + rep); }

    html re-enable right click

    https://stackoverflow.com/questions/21335136/how-to-re-enable-right-click-so-that-i-can-inspect-html-elements-in-chrome/21335527 Open dev tools (Shift+Control+i). Select the "Elements" tab, and then the "Event Listeners" tab. Hover over the elements/listener. A "Remove" button will show up. Click "Remove". Another possible way, when the blocking function is made with jquery, use: $(document).unbind(); It will clear all the onmousedown and contextmenu events attributed dynamically, that can't be erased with document.contextmenu=null; etc. some code did a re-bind: $(document).bind("contextmenu",function(e){if(!$('#easyy').length)e.preventDefault();}); If none of the other comments works, just do, open console line command and type: document.oncontextmenu = null;

    encryption hex_md5.js

    https://gist.github.com/Xarrow/e8d14b982c2763954230 <script type="text/javascript" src="md5.js"></script> <script> for(var k=1; k<=310; k++){ $('#mustWatch').append( hex_md5(String(k)) + "<br>") } </script>

    generate random array

    waitingList = Array(10).fill().map(() => Math.round(Math.random() * totalLength)) // set unique waitingList = [...new Set(waitingList)] if (localStorage.getItem(waitingList) === null) { initWaitList() }else{ waitList = localStorage.getItem(waitingList).split(",").map(Number) if(waitList == [0]){ initWaitList() } } function initWaitList() { // generate random pointers waitList = Array(10).fill().map(() => Math.round(Math.random() * totalLength)) waitList = [...new Set(waitList)] // set unique localStorage.setItem(waitingList, waitList) } function randomWL() { pointerList = waitList if(waitList.length > 10){ pointerList.splice(10, (pointerList.length - 10)); } newPointer = pointerList[Math.floor(Math.random() * pointerList.length)]; while(newPointer == topicpointer){ newPointer = pointerList[Math.floor(Math.random() * pointerList.length)]; } topicpointer = newPointer; showTopic(); } function addtoWL() { console.log(topicpointer)waitList.push(topicpointer)waitList = Array.from(new Set(waitList))localStorage.setItem(waitingList, waitList)alert("added topic: " +topicpointer+ "\nwaitList: " + waitList) }

    Create a Cookie with JavaScript

    JavaScript can create, read, and delete cookies with the document.cookie property. With JavaScript, a cookie can be created like this: document.cookie = "username=John Doe"; You can also add an expiry date (in UTC time). By default, the cookie is deleted when the browser is closed: document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC"; With a path parameter, you can tell the browser what path the cookie belongs to. By default, the cookie belongs to the current page. document.cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/";

    Read a Cookie with JavaScript

    With JavaScript, cookies can be read like this: let x = document.cookie; document.cookie will return all cookies in one string much like: cookie1=value; cookie2=value; cookie3=value;

    Change a Cookie with JavaScript

    With JavaScript, you can change a cookie the same way as you create it: document.cookie = "username=John Smith; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/"; The old cookie is overwritten.

    Delete a Cookie with JavaScript

    Deleting a cookie is very simple. You don't have to specify a cookie value when you delete a cookie. Just set the expires parameter to a past date: document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; You should define the cookie path to ensure that you delete the right cookie. Some browsers will not let you delete a cookie if you don't specify the path.

    The Cookie String

    The document.cookie property looks like a normal text string. But it is not. Even if you write a whole cookie string to document.cookie, when you read it out again, you can only see the name-value pair of it. If you set a new cookie, older cookies are not overwritten. The new cookie is added to document.cookie, so if you read document.cookie again you will get something like: cookie1 = value; cookie2 = value; If you want to find the value of one specified cookie, you must write a JavaScript function that searches for the cookie value in the cookie string.

    JavaScript Cookie Example

    In the example to follow, we will create a cookie that stores the name of a visitor. The first time a visitor arrives to the web page, he/she will be asked to fill in his/her name. The name is then stored in a cookie. The next time the visitor arrives at the same page, he/she will get a welcome message. For the example we will create 3 JavaScript functions:
  • A function to set a cookie value
  • A function to get a cookie value
  • A function to check a cookie value
  • A Function to Set a Cookie

    First, we create a function that stores the name of the visitor in a cookie variable: Example function setCookie(cname, cvalue, exdays) { const d = new Date(); d.setTime(d.getTime() + (exdays*24*60*60*1000)); let expires = "expires="+ d.toUTCString(); document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; } Example explained: The parameters of the function above are the name of the cookie (cname), the value of the cookie (cvalue), and the number of days until the cookie should expire (exdays). The function sets a cookie by adding together the cookiename, the cookie value, and the expires string.

    A Function to Get a Cookie

    Then, we create a function that returns the value of a specified cookie: Example function getCookie(cname) { let name = cname + "="; let decodedCookie = decodeURIComponent(document.cookie); let ca = decodedCookie.split(';'); for(let i = 0; i <ca.length; i++) { let c = ca[i]; while (c.charAt(0) == ' ') { c = c.substring(1); } if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); } } return ""; } Function explained: Take the cookiename as parameter (cname). Create a variable (name) with the text to search for (cname + "="). Decode the cookie string, to handle cookies with special characters, e.g. '$' Split document.cookie on semicolons into an array called ca (ca = decodedCookie.split(';')). Loop through the ca array (i = 0; i < ca.length; i++), and read out each value c = ca[i]). If the cookie is found (c.indexOf(name) == 0), return the value of the cookie (c.substring(name.length, c.length). If the cookie is not found, return "".

    A Function to Check a Cookie

    Last, we create the function that checks if a cookie is set. If the cookie is set it will display a greeting. If the cookie is not set, it will display a prompt box, asking for the name of the user, and stores the username cookie for 365 days, by calling the setCookie function: Example function checkCookie() { let username = getCookie("username"); if (username != "") { alert("Welcome again " + username); } else { username = prompt("Please enter your name:", ""); if (username != "" && username != null) { setCookie("username", username, 365); } } }

    All Together Now

    Example function setCookie(cname, cvalue, exdays) { const d = new Date(); d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); let expires = "expires="+d.toUTCString(); document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; } function getCookie(cname) { let name = cname + "="; let ca = document.cookie.split(';'); for(let i = 0; i < ca.length; i++) { let c = ca[i]; while (c.charAt(0) == ' ') { c = c.substring(1); } if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); } } return ""; } function checkCookie() { let user = getCookie("username"); if (user != "") { alert("Welcome again " + user); } else { user = prompt("Please enter your name:", ""); if (user != "" && user != null) { setCookie("username", user, 365); } } } Try it Yourself » The example above runs the checkCookie() function when the page loads.

    blank return

    var x; // x is undefined alert(x); // shows "undefined" alert(!x); // shows "true" alert(x==false); // shows "false" So, It is a good practice to return "false" instead of a blank return. That way you make it all uniform and make life easy for other programmers. alert("type: " + typeof x+", value: "+x); alert("type: " + typeof !x+", value: "+!x); alert("type: " + typeof x==false +", value: "+ x==false);

    speechSynthesis.speak()

    speechSynthesis.speak() without user activation is no longer allowed If you set your site address as "trusted" in chrome://settings/content/sound it seems to enable sound and speech synthesis even without user interactions. User interaction means: click, dblclick, mouseup, pointerup, reset, submit etc. So, if you want to run speechSynthesis.speak(); without real user interaction, then you just create temporary user interaction using a method like .click(), etc. https://stackoverflow.com/questions/46551705/speechsynthesis-speaking-never-true A simple hack, without needing a real user activity, is to execute a click event on a hidden button like so. document.querySelector('button').click(); var msg = new SpeechSynthesisUtterance('Test'); window.onload = function(){ var u = new SpeechSynthesisUtterance('All is Ok'); u.text = 'Hello World'; u.lang = 'en-US'; u.rate = 1; u.pitch = .4; speechSynthesis.speak(u); } function doSpeech() { var synth = window.speechSynthesis; var utterance1 = new SpeechSynthesisUtterance('How about we say this now? This is quite a long sentence to say. Make it longer !'); var utterance2 = new SpeechSynthesisUtterance('We should say another sentence too, just to be on the safe side. even longer !'); synth.speak(utterance1); // If you check immediately (js code executed in less than ms) the // status won't be true if (synth.speaking) { console.log("This is usually printed, if the utterance uses the default voice of the browser (native)"); } // Wait 500ms to check for the status of the utterance setTimeout(function(){ if (synth.speaking) { console.log("This will be printed if starts after 500ms :)"); } }, 500); } doSpeech(); In my case, both of the console.log statements are being printed. But if in your case it isn't being printed, execute your code only after the start event of the utterance: function doSpeech() { var synth = window.speechSynthesis; var msg = new SpeechSynthesisUtterance(); msg.text = "We should say another sentence too, just to be on the safe side. even longer !"; msg.addEventListener('start', function() { if(synth.speaking){ console.log("This will be printed !"); } }); synth.speak(msg); } doSpeech(); function doSpeech() { var synth = window.speechSynthesis; var utterance1 = new SpeechSynthesisUtterance('How about we say this now? This is quite a long sentence to say. Make it longer !'); var utterance2 = new SpeechSynthesisUtterance('We should say another sentence too, just to be on the safe side. even longer !'); synth.speak(utterance1); // If you check immediately (js code executed in less than ms) the // status won't be true if (synth.speaking) { console.log("This is usually printed, if the utterance uses the default voice of the browser (native)"); } // Wait 500ms to check for the status of the utterance setTimeout(function(){ if (synth.speaking) { console.log("This will be printed if starts after 500ms :)"); } }, 500); } doSpeech(); In my case, both of the console.log statements are being printed. But if in your case it isn't being printed, execute your code only after the start event of the utterance: function doSpeech() { var synth = window.speechSynthesis; var msg = new SpeechSynthesisUtterance(); msg.text = "We should say another sentence too, just to be on the safe side. even longer !"; msg.addEventListener('start', function() { if(synth.speaking){ console.log("This will be printed !"); } }); synth.speak(msg); } doSpeech();

    speak functions

    function polyphone(str){ var findstr = ["應勿","則省","使更","不入","所好","所惡","號泣","喪","長呼","尊長","見能","遇長","長無","下車","待","朝起","便溺","切","冠服","不貴","循分","稱家","從容","跛倚","不問","還","擅為","為先","未的","地同載","同","行高","訾","不欲","不媚","不力","長浮","為限","滯塞","几","不敬","卷"]; var rplcstr = ["硬勿","則醒","使庚","轐入","所耗","所勿","毫泣","桑","掌呼","尊掌","現能","遇掌","掌無","下居","帶","招起","便尿","竊","官服","轐貴","循份","秤家","匆容","必倚","轐問","環","擅圍","圍先","未笛","弟銅在","銅","幸高","子","轐欲","轐媚","轐力","掌浮","圍限","滯色","雞","轐敬","倦"]; var regex; for (var i = 0; i < findstr.length; i++) { regex = new RegExp(findstr[i], "g"); str= str.replace(regex, rplcstr[i]); } return str; } function getSpeechParagraphs(){ var ret = "弟子規"; var pfs=document.getElementsByName('pf'); for (i = 0; i < pfs.length; i++) { s=pfs[i].innerText.replace(/ /g, ","); s=s.replace(/[\n\r]/g,','); ret=ret+'。 '+s; } return polyphone(ret); } if ('speechSynthesis' in window) { var paragraphs=getSpeechParagraphs(); var synth = window.speechSynthesis; synth.cancel(); var u = new SpeechSynthesisUtterance(); u.rate=0.8; u.pitch=1; u.volume=1; u.text=paragraphs; u.lang = 'zh-TW'; var u2 = new SpeechSynthesisUtterance(); u2.rate=0.7; u2.pitch=1; u2.volume=1; u2.lang = 'zh-TW'; function speak() { speechSynthesis.speak(new SpeechSynthesisUtterance("hello world")); speechSynthesis.speak(u); } var u = new SpeechSynthesisUtterance('All is Ok'); u.text = 'Hello World'; u.lang = 'en-US'; u.rate = 1; u.pitch = .4; function speech_selection(){ var selectedText = ""; if(window.getSelection){ selectedText = window.getSelection(); }else if(document.getSelection){ selectedText = document.getSelection(); }else if(document.selection){ selectedText = document.selection.createRange().text; } if(selectedText != ""){ selectedText = selectedText.toString(); if(synth.speaking){synth.cancel();} var voices = synth.getVoices(); for(var i=0;i < voices.length;i++){ if ( voices[i].localService==true && voices[i].lang.toLowerCase() =='zh-tw'){ u2.voice=voices[i]; break; } } u2.text=polyphone(selectedText); synth.speak(u2); } } function doSpeech() { var synth = window.speechSynthesis; var utterance1 = new SpeechSynthesisUtterance('How about we say this now? This is quite a long sentence to say. Make it longer !'); var utterance2 = new SpeechSynthesisUtterance('We should say another sentence too, just to be on the safe side. even longer !'); synth.speak(utterance1); // If you check immediately (js code executed in less than ms) the // status won't be true if (synth.speaking) { console.log("This is usually printed, if the utterance uses the default voice of the browser (native)"); } // Wait 500ms to check for the status of the utterance setTimeout(function(){ if (synth.speaking) { console.log("This will be printed if starts after 500ms :)"); } }, 500); } doSpeech();

    speak functions

    function polyphone(str){ var findstr = ["應勿","則省","使更","不入","所好","所惡","號泣","喪","長呼","尊長","見能","遇長","長無","下車","待","朝起","便溺","切","冠服","不貴","循分","稱家","從容","跛倚","不問","還","擅為","為先","未的","地同載","同","行高","訾","不欲","不媚","不力","長浮","為限","滯塞","几","不敬","卷"]; var rplcstr = ["硬勿","則醒","使庚","轐入","所耗","所勿","毫泣","桑","掌呼","尊掌","現能","遇掌","掌無","下居","帶","招起","便尿","竊","官服","轐貴","循份","秤家","匆容","必倚","轐問","環","擅圍","圍先","未笛","弟銅在","銅","幸高","子","轐欲","轐媚","轐力","掌浮","圍限","滯色","雞","轐敬","倦"]; var regex; for (var i = 0; i < findstr.length; i++) { regex = new RegExp(findstr[i], "g"); str= str.replace(regex, rplcstr[i]); } return str; } function getSpeechParagraphs(){ var ret = "弟子規"; var pfs=document.getElementsByName('pf'); for (i = 0; i < pfs.length; i++) { s=pfs[i].innerText.replace(/ /g, ","); s=s.replace(/[\n\r]/g,','); ret=ret+'。 '+s; } return polyphone(ret); } if ('speechSynthesis' in window) { var paragraphs=getSpeechParagraphs(); var synth = window.speechSynthesis; synth.cancel(); var u = new SpeechSynthesisUtterance(); u.rate=0.8; u.pitch=1; u.volume=1; u.text=paragraphs; u.lang = 'zh-TW'; var u2 = new SpeechSynthesisUtterance(); u2.rate=0.7; u2.pitch=1; u2.volume=1; u2.lang = 'zh-TW'; function speak() { speechSynthesis.speak(new SpeechSynthesisUtterance("hello world")); speechSynthesis.speak(u); } var u = new SpeechSynthesisUtterance('All is Ok'); u.text = 'Hello World'; u.lang = 'en-US'; u.rate = 1; u.pitch = .4; function speech_selection(){ var selectedText = ""; if(window.getSelection){ selectedText = window.getSelection(); }else if(document.getSelection){ selectedText = document.getSelection(); }else if(document.selection){ selectedText = document.selection.createRange().text; } if(selectedText != ""){ selectedText = selectedText.toString(); if(synth.speaking){synth.cancel();} var voices = synth.getVoices(); for(var i=0;i < voices.length;i++){ if ( voices[i].localService==true && voices[i].lang.toLowerCase() =='zh-tw'){ u2.voice=voices[i]; break; } } u2.text=polyphone(selectedText); synth.speak(u2); } } function doSpeech() { var synth = window.speechSynthesis; var utterance1 = new SpeechSynthesisUtterance('How about we say this now? This is quite a long sentence to say. Make it longer !'); var utterance2 = new SpeechSynthesisUtterance('We should say another sentence too, just to be on the safe side. even longer !'); synth.speak(utterance1); // If you check immediately (js code executed in less than ms) the // status won't be true if (synth.speaking) { console.log("This is usually printed, if the utterance uses the default voice of the browser (native)"); } // Wait 500ms to check for the status of the utterance setTimeout(function(){ if (synth.speaking) { console.log("This will be printed if starts after 500ms :)"); } }, 500); } doSpeech();

    showMov

    function showMov() { idstring = "#topic-" + topicpointer; $(idstring).click() }

    table of table of contents

    create div #totoc put script at page bottom var totoc = $('#totoc'); $("a span.orange").each(function(i) { var totopic = $(this), totopicNumber = i; totopicLength = totopicNumber +1; totoc.append(''+totopic.text()+''+" "); totopic.attr('id', 'totopic-' + totopicNumber); });

    to write html

    document.write('')

    Modules, introduction

    https://javascript.info/modules-intro As our application grows bigger, we want to split it into multiple files, so called “modules”. A module may contain a class or a library of functions for a specific purpose. For a long time, JavaScript existed without a language-level module syntax. That wasn’t a problem, because initially scripts were small and simple, so there was no need. But eventually scripts became more and more complex, so the community invented a variety of ways to organize code into modules, special libraries to load modules on demand. To name some (for historical reasons): AMD – one of the most ancient module systems, initially implemented by the library require.js. CommonJS – the module system created for Node.js server. UMD – one more module system, suggested as a universal one, compatible with AMD and CommonJS. Now all these slowly become a part of history, but we still can find them in old scripts. The language-level module system appeared in the standard in 2015, gradually evolved since then, and is now supported by all major browsers and in Node.js. So we’ll study the modern JavaScript modules from now on.

    What is a module?

    A module is just a file. One script is one module. As simple as that. Modules can load each other and use special directives export and import to interchange functionality, call functions of one module from another one: export keyword labels variables and functions that should be accessible from outside the current module. import allows the import of functionality from other modules. For instance, if we have a file sayHi.js exporting a function: // 📁 sayHi.js export function sayHi(user) { alert(`Hello, ${user}!`); } …Then another file may import and use it: // 📁 main.js import {sayHi} from './sayHi.js'; alert(sayHi); // function... sayHi('John'); // Hello, John! The import directive loads the module by path ./sayHi.js relative to the current file, and assigns exported function sayHi to the corresponding variable. Let’s run the example in-browser. As modules support special keywords and features, we must tell the browser that a script should be treated as a module, by using the attribute <script type="module">. Like this: <iframe src="https://javascript.info/article/modules-intro/say/"></iframe> export function sayHi(user) { return `Hello, ${user}!`; } <!doctype html> <script type="module"> import {sayHi} from './say.js'; document.body.innerHTML = sayHi('John'); </script> The browser automatically fetches and evaluates the imported module (and its imports if needed), and then runs the script. Modules work only via HTTP(s), not locally If you try to open a web-page locally, via file:// protocol, you’ll find that import/export directives don’t work. Use a local web-server, such as static-server or use the “live server” capability of your editor, such as VS Code Live Server Extension to test modules.

    Core module features

    What’s different in modules, compared to “regular” scripts? There are core features, valid both for browser and server-side JavaScript.

    Always “use strict”

    Modules always work in strict mode. E.g. assigning to an undeclared variable will give an error. <script type="module"> a = 5; // error </script>

    Module-level scope

    Each module has its own top-level scope. In other words, top-level variables and functions from a module are not seen in other scripts. In the example below, two scripts are imported, and hello.js tries to use user variable declared in user.js. It fails, because it’s a separate module (you’ll see the error in the console): <iframe src="https://javascript.info/article/modules-intro/scopes/"></iframe> alert(user); // no such variable (each module has independent variables) let user = "John"; <!doctype html> <script type="module" src="user.js"></script> <script type="module" src="hello.js"></script> Modules should export what they want to be accessible from outside and import what they need. user.js should export the user variable. hello.js should import it from user.js module. In other words, with modules we use import/export instead of relying on global variables. This is the correct variant: ⁢iframe src="https://javascript.info/article/modules-intro/scopes-working/"></iframe> import {user} from './user.js'; document.body.innerHTML = user; // John export let user = "John"; <!doctype html> <script type="module" src="hello.js"></script> In the browser, if we talk about HTML pages, independent top-level scope also exists for each <script type="module">. Here are two scripts on the same page, both type="module". They don’t see each other’s top-level variables: <script type="module"> // The variable is only visible in this module script let user = "John"; </script> <script type="module"> alert(user); // Error: user is not defined </script> Please note: In the browser, we can make a variable window-level global by explicitly assigning it to a window property, e.g. window.user = "John". Then all scripts will see it, both with type="module" and without it. That said, making such global variables is frowned upon. Please try to avoid them.

    A module code is evaluated only the first time when imported

    If the same module is imported into multiple other modules, its code is executed only once, upon the first import. Then its exports are given to all further importers. The one-time evaluation has important consequences, that we should be aware of. Let’s see a couple of examples. First, if executing a module code brings side-effects, like showing a message, then importing it multiple times will trigger it only once – the first time: // 📁 alert.js alert("Module is evaluated!"); // Import the same module from different files // 📁 1.js import `./alert.js`; // Module is evaluated! // 📁 2.js import `./alert.js`; // (shows nothing) The second import shows nothing, because the module has already been evaluated. There’s a rule: top-level module code should be used for initialization, creation of module-specific internal data structures. If we need to make something callable multiple times – we should export it as a function, like we did with sayHi above. Now, let’s consider a deeper example. Let’s say, a module exports an object: // 📁 admin.js export let admin = { name: "John" }; If this module is imported from multiple files, the module is only evaluated the first time, admin object is created, and then passed to all further importers. All importers get exactly the one and only admin object: // 📁 1.js import {admin} from './admin.js'; admin.name = "Pete"; // 📁 2.js import {admin} from './admin.js'; alert(admin.name); // Pete // Both 1.js and 2.js reference the same admin object // Changes made in 1.js are visible in 2.js As you can see, when 1.js changes the name property in the imported admin, then 2.js can see the new admin.name. That’s exactly because the module is executed only once. Exports are generated, and then they are shared between importers, so if something changes the admin object, other modules will see that. Such behavior is actually very convenient, because it allows us to configure modules. In other words, a module can provide a generic functionality that needs a setup. E.g. authentication needs credentials. Then it can export a configuration object expecting the outer code to assign to it. Here’s the classical pattern: A module exports some means of configuration, e.g. a configuration object. On the first import we initialize it, write to its properties. The top-level application script may do that. Further imports use the module. For instance, the admin.js module may provide certain functionality (e.g. authentication), but expect the credentials to come into the config object from outside: // 📁 admin.js export let config = { }; export function sayHi() { alert(`Ready to serve, ${config.user}!`); } Here, admin.js exports the config object (initially empty, but may have default properties too). Then in init.js, the first script of our app, we import config from it and set config.user: // 📁 init.js import {config} from './admin.js'; config.user = "Pete"; …Now the module admin.js is configured. Further importers can call it, and it correctly shows the current user: // 📁 another.js import {sayHi} from './admin.js'; sayHi(); // Ready to serve, Pete!

    import.meta

    The object import.meta contains the information about the current module. Its content depends on the environment. In the browser, it contains the URL of the script, or a current webpage URL if inside HTML: <script type="module"> alert(import.meta.url); // script URL // for an inline script - the URL of the current HTML-page </script>

    In a module, “this” is undefined

    That’s kind of a minor feature, but for completeness we should mention it. In a module, top-level this is undefined. Compare it to non-module scripts, where this is a global object: <script> alert(this); // window </script> <script type="module"> alert(this); // undefined </script>

    Browser-specific features

    There are also several browser-specific differences of scripts with type="module" compared to regular ones. You may want to skip this section for now if you’re reading for the first time, or if you don’t use JavaScript in a browser.

    Module scripts are deferred

    Module scripts are always deferred, same effect as defer attribute (described in the chapter Scripts: async, defer), for both external and inline scripts. In other words: downloading external module scripts <script type="module" src="..."> doesn’t block HTML processing, they load in parallel with other resources. module scripts wait until the HTML document is fully ready (even if they are tiny and load faster than HTML), and then run. relative order of scripts is maintained: scripts that go first in the document, execute first. As a side-effect, module scripts always “see” the fully loaded HTML-page, including HTML elements below them. For instance: <script type="module"> alert(typeof button); // object: the script can 'see' the button below // as modules are deferred, the script runs after the whole page is loaded </script> Compare to regular script below: <script> alert(typeof button); // button is undefined, the script can't see elements below // regular scripts run immediately, before the rest of the page is processed </script> <button id="button">Button</button> Please note: the second script actually runs before the first! So we’ll see undefined first, and then object. That’s because modules are deferred, so we wait for the document to be processed. The regular script runs immediately, so we see its output first. When using modules, we should be aware that the HTML page shows up as it loads, and JavaScript modules run after that, so the user may see the page before the JavaScript application is ready. Some functionality may not work yet. We should put “loading indicators”, or otherwise ensure that the visitor won’t be confused by that.

    Async works on inline scripts

    For non-module scripts, the async attribute only works on external scripts. Async scripts run immediately when ready, independently of other scripts or the HTML document. For module scripts, it works on inline scripts as well. For example, the inline script below has async, so it doesn’t wait for anything. It performs the import (fetches ./analytics.js) and runs when ready, even if the HTML document is not finished yet, or if other scripts are still pending. That’s good for functionality that doesn’t depend on anything, like counters, ads, document-level event listeners. <!-- all dependencies are fetched (analytics.js), and the script runs --> <!-- doesn't wait for the document or other <script> tags --> <script async type="module"> import {counter} from './analytics.js'; counter.count(); </script>

    External scripts

    External scripts that have type="module" are different in two aspects: External scripts with the same src run only once: <!-- the script my.js is fetched and executed only once --> <script type="module" src="my.js"></script> <script type="module" src="my.js"></script> External scripts that are fetched from another origin (e.g. another site) require CORS headers, as described in the chapter Fetch: Cross-Origin Requests. In other words, if a module script is fetched from another origin, the remote server must supply a header Access-Control-Allow-Origin allowing the fetch. <!-- another-site.com must supply Access-Control-Allow-Origin --> <!-- otherwise, the script won't execute --> <script type="module" src="http://another-site.com/their.js"></script> That ensures better security by default.

    No “bare” modules allowed

    In the browser, import must get either a relative or absolute URL. Modules without any path are called “bare” modules. Such modules are not allowed in import. For instance, this import is invalid: import {sayHi} from 'sayHi'; // Error, "bare" module // the module must have a path, e.g. './sayHi.js' or wherever the module is Certain environments, like Node.js or bundle tools allow bare modules, without any path, as they have their own ways for finding modules and hooks to fine-tune them. But browsers do not support bare modules yet.

    Compatibility, “nomodule”

    Old browsers do not understand type="module". Scripts of an unknown type are just ignored. For them, it’s possible to provide a fallback using the nomodule attribute: <script type="module"> alert("Runs in modern browsers"); </script> <script nomodule> alert("Modern browsers know both type=module and nomodule, so skip this") alert("Old browsers ignore script with unknown type=module, but execute this."); </script>

    Build tools

    In real-life, browser modules are rarely used in their “raw” form. Usually, we bundle them together with a special tool such as Webpack and deploy to the production server. One of the benefits of using bundlers – they give more control over how modules are resolved, allowing bare modules and much more, like CSS/HTML modules. Build tools do the following: Take a “main” module, the one intended to be put in <script type="module"> in HTML. Analyze its dependencies: imports and then imports of imports etc. Build a single file with all modules (or multiple files, that’s tunable), replacing native import calls with bundler functions, so that it works. “Special” module types like HTML/CSS modules are also supported. In the process, other transformations and optimizations may be applied: Unreachable code removed. Unused exports removed (“tree-shaking”). Development-specific statements like console and debugger removed. Modern, bleeding-edge JavaScript syntax may be transformed to older one with similar functionality using Babel. The resulting file is minified (spaces removed, variables replaced with shorter names, etc). If we use bundle tools, then as scripts are bundled together into a single file (or few files), import/export statements inside those scripts are replaced by special bundler functions. So the resulting “bundled” script does not contain any import/export, it doesn’t require type="module", and we can put it into a regular script: <!-- Assuming we got bundle.js from a tool like Webpack --> <script src="bundle.js"></script> That said, native modules are also usable. So we won’t be using Webpack here: you can configure it later.

    Summary

    To summarize, the core concepts are: A module is a file. To make import/export work, browsers need <script type="module">. Modules have several differences: Deferred by default. Async works on inline scripts. To load external scripts from another origin (domain/protocol/port), CORS headers are needed. Duplicate external scripts are ignored. Modules have their own, local top-level scope and interchange functionality via import/export. Modules always use strict. Module code is executed only once. Exports are created once and shared between importers. When we use modules, each module implements the functionality and exports it. Then we use import to directly import it where it’s needed. The browser loads and evaluates the scripts automatically. In production, people often use bundlers such as Webpack to bundle modules together for performance and other reasons. In the next chapter we’ll see more examples of modules, and how things can be exported/imported.

    object constructor function

    function Person(first, last, age, eye) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eye; } // Create a Person object const myFather = new Person("John", "Doe", 50, "blue"); // Display age document.getElementById("demo").innerHTML = "My father is " + myFather.age + ".";

    Object Types (Blueprints) (Classes)

    The examples from the previous chapters are limited. They only create single objects. Sometimes we need a "blueprint" for creating many objects of the same "type". The way to create an "object type", is to use an object constructor function. In the example above, function Person() is an object constructor function. Objects of the same type are created by calling the constructor function with the new keyword: const myFather = new Person("John", "Doe", 50, "blue"); const myMother = new Person("Sally", "Rally", 48, "green"); Adding a Property to an Object Adding a new property to an existing object is easy: Example myFather.nationality = "English"; The property will be added to myFather. Not to myMother. (Not to any other person objects). Adding a Method to an Object Adding a new method to an existing object is easy: Example myFather.name = function() { return this.firstName + " " + this.lastName; }; The method will be added to myFather. Not to myMother. (Not to any other person objects). Adding a Property to a Constructor You cannot add a new property to an object constructor the same way you add a new property to an existing object: Example Person.nationality = "English"; To add a new property to a constructor, you must add it to the constructor function: Example function Person(first, last, age, eyecolor) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eyecolor; this.nationality = "English"; } This way object properties can have default values. Adding a Method to a Constructor Your constructor function can also define methods: Example function Person(first, last, age, eyecolor) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eyecolor; this.name = function() { return this.firstName + " " + this.lastName; }; } You cannot add a new method to an object constructor the same way you add a new method to an existing object. Adding methods to an object constructor must be done inside the constructor function: Example function Person(firstName, lastName, age, eyeColor) { this.firstName = firstName; this.lastName = lastName; this.age = age; this.eyeColor = eyeColor; this.changeName = function(name) { this.lastName = name; }; } The changeName() function assigns the value of name to the person's lastName property. Now You Can Try: myMother.changeName("Doe"); JavaScript knows which person you are talking about by "substituting" this with myMother. Built-in JavaScript Constructors JavaScript has built-in constructors for native objects: new String() // A new String object new Number() // A new Number object new Boolean() // A new Boolean object new Object() // A new Object object new Array() // A new Array object new RegExp() // A new RegExp object new Function() // A new Function object new Date() // A new Date object The Math() object is not in the list. Math is a global object. The new keyword cannot be used on Math. As you can see above, JavaScript has object versions of the primitive data types String, Number, and Boolean. But there is no reason to create complex objects. Primitive values are much faster: Use string literals "" instead of new String(). Use number literals 50 instead of new Number(). Use boolean literals true / false instead of new Boolean(). Use object literals {} instead of new Object(). Use array literals [] instead of new Array(). Use pattern literals /()/ instead of new RegExp(). Use function expressions () {} instead of new Function(). Example let x1 = ""; // new primitive string let x2 = 0; // new primitive number let x3 = false; // new primitive boolean const x4 = {}; // new Object object const x5 = []; // new Array object const x6 = /()/ // new RegExp object const x7 = function(){}; // new function String Objects Normally, strings are created as primitives: firstName = "John" But strings can also be created as objects using the new keyword: firstName = new String("John") Number Objects Normally, numbers are created as primitives: x = 30 But numbers can also be created as objects using the new keyword: x = new Number(30) Boolean Objects Normally, booleans are created as primitives: x = false But booleans can also be created as objects using the new keyword: x = new Boolean(false)

    get current scroll height

    document.documentElement.scrollTop || document.body.scrollTop scrollheight jquery $('#toc').prop('scrollHeight') Correct ways in jQuery are $('#test')[0].scrollHeight OR $('#test').prop('scrollHeight') OR $('#test').get(0).scrollHeight jquery on scroll Trigger the scroll event for the selected elements: $(selector).scroll() ​Attach a function to the scroll event: $(selector).scroll(function) determine scrollHeight using jquery $('#test').keyup(function() { var height = $(this).scrollTop(); var initHeight = 5; if(initHeight < height ) { $(this).css({'height':'8rem'}); } })

    Maps

    https://www.w3schools.com/js/js_object_maps.asp A Map holds key-value pairs where the keys can be any datatype. A Map remembers the original insertion order of the keys. A Map has a property that represents the size of the map.

    Map Methods

    Method Description new Map() Creates a new Map object set() Sets the value for a key in a Map get() Gets the value for a key in a Map clear() Removes all the elements from a Map delete() Removes a Map element specified by a key has() Returns true if a key exists in a Map forEach() Invokes a callback for each key/value pair in a Map entries() Returns an iterator object with the [key, value] pairs in a Map keys() Returns an iterator object with the keys in a Map values() Returns an iterator object of the values in a Map Property Description size Returns the number of Map elements

    How to Create a Map

    You can create a JavaScript Map by:
  • Passing an Array to new Map()
  • Create a Map and use Map.set()
  • new Map()

    You can create a Map by passing an Array to the new Map() constructor: Example // Create a Map const fruits = new Map([ ["apples", 500], ["bananas", 300], ["oranges", 200] ]);

    Map.set()

    You can add elements to a Map with the set() method: Example // Create a Map const fruits = new Map(); // Set Map Values fruits.set("apples", 500); fruits.set("bananas", 300); fruits.set("oranges", 200); The set() method can also be used to change existing Map values: Example fruits.set("apples", 500);

    Map.get()

    The get() method gets the value of a key in a Map: Example fruits.get("apples"); // Returns 500 // Creating a map object var myMap = new Map(); // Adding [key, value] pair to the map myMap.set(0, 'GeeksforGeeks'); // Displaying the element which is associated with // the key '0' using Map.get() method document.write(myMap.get(0)); Output: "GeeksforGeeks"

    Map.size

    The size property returns the number of elements in a Map: Example fruits.size;

    Map.delete()

    The delete() method removes a Map element: Example fruits.delete("apples");

    Map.clear()

    The clear() method removes all the elements from a Map: Example fruits.clear();

    Map.has()

    The has() method returns true if a key exists in a Map: Example fruits.has("apples"); fruits.delete("apples"); fruits.has("apples");

    Maps are Objects

    typeof returns object: Example // Returns object: typeof fruits; instanceof Map returns true: Example // Returns true: fruits instanceof Map;

    JavaScript Objects vs Maps

    Differences between JavaScript Objects and Maps:

    Iterable Object Not directly iterable Map Directly iterable Size Object Do not have a size property Map Have a size property Key Types Object Keys must be Strings (or Symbols) Map Keys can be any datatype Key Order Object Keys are not well ordered Map Keys are ordered by insertion Defaults Object Have default keys Map Do not have default keys

    Map.forEach()

    The forEach() method invokes a callback for each key/value pair in a Map: Example // List all entries let text = ""; fruits.forEach (function(value, key) { text += key + ' = ' + value; })

    Map.keys()

    The keys() method returns an iterator object with the keys in a Map: Example // List all keys let veggies = ""; for (const x of fruits.keys()) { veggies += x; }

    Map.values()

    The values method returns an iterator object with the values in a Map: Example // Sum all values let total = 0; for (const x of fruits.values()) { total += x; }

    Map.entries()

    The entries() method returns an iterator object with the [key,values] in a Map: Example // List all entries let text = ""; for (const x of fruits.entries()) { text += x; }

    Objects as Keys

    Being able to use objects as keys is an important Map feature. Example // Create Objects const apples = {name: 'Apples'}; const bananas = {name: 'Bananas'}; const oranges = {name: 'Oranges'}; // Create a Map const fruits = new Map(); // Add new Elements to the Map fruits.set(apples, 500); fruits.set(bananas, 300); fruits.set(oranges, 200); Remember: The key is an object (apples), not a string ("apples"): Example fruits.get("apples"); // Returns undefined

    56 个 JavaScript 实用函数

    1. 数字操作

    生成指定范围随机数

    export const randomNum = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;

    数字千分位分隔

    export const format = (n) => { let num = n.toString(); let len = num.length; if (len <= 3) { return num; } else { let temp = ''; let remainder = len % 3; if (remainder > 0) { // 不是3的整数倍 return num.slice(0, remainder) + ',' + num.slice(remainder, len).match(/\d{3}/g).join(',') + temp; } else { // 3的整数倍 return num.slice(0, len).match(/\d{3}/g).join(',') + temp; } } }

    2. 数组操作

    数组乱序

    export const arrScrambling = (arr) => { for (let i = 0; i < arr.length; i++) { const randomIndex = Math.round(Math.random() * (arr.length - 1 - i)) + i; [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]]; } return arr; }

    数组扁平化

    export const flatten = (arr) => { let result = []; for(let i = 0; i < arr.length; i++) { if(Array.isArray(arr[i])) { result = result.concat(flatten(arr[i])); } else { result.push(arr[i]); } } return result; }

    数组中获取随机数

    export const sample = arr => arr[Math.floor(Math.random() * arr.length)];

    3. 字符串操作

    生成随机字符串

    export const randomString = (len) => { let chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz123456789'; let strLen = chars.length; let randomStr = ''; for (let i = 0; i < len; i++) { randomStr += chars.charAt(Math.floor(Math.random() * strLen)); } return randomStr; };

    字符串首字母大写

    export const fistLetterUpper = (str) => { return str.charAt(0).toUpperCase() + str.slice(1); };

    手机号中间四位变成*

    export const telFormat = (tel) => { tel = String(tel); return tel.substr(0,3) + "****" + tel.substr(7); };

    驼峰命名转换成短横线命名

    export const getKebabCase = (str) => { return str.replace(/[A-Z]/g, (item) => '-' + item.toLowerCase()) }

    短横线命名转换成驼峰命名

    export const getCamelCase = (str) => { return str.replace( /-([a-z])/g, (i, item) => item.toUpperCase()) }

    全角转换为半角

    export const toCDB = (str) => { let result = ""; for (let i = 0; i < str.length; i++) { code = str.charCodeAt(i); if (code >= 65281 && code <= 65374) { result += String.fromCharCode(str.charCodeAt(i) - 65248); } else if (code == 12288) { result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32); } else { result += str.charAt(i); } } return result; }

    半角转换为全角

    export const toDBC = (str) => { let result = ""; for (let i = 0; i < str.length; i++) { code = str.charCodeAt(i); if (code >= 33 && code <= 126) { result += String.fromCharCode(str.charCodeAt(i) + 65248); } else if (code == 32) { result += String.fromCharCode(str.charCodeAt(i) + 12288 - 32); } else { result += str.charAt(i); } } return result; }

    4. 格式转化

    数字转化为大写金额

    export const digitUppercase = (n) => { const fraction = ['角', '分']; const digit = [ '零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖' ]; const unit = [ ['元', '万', '亿'], ['', '拾', '佰', '仟'] ]; n = Math.abs(n); let s = ''; for (let i = 0; i < fraction.length; i++) { s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, ''); } s = s || '整'; n = Math.floor(n); for (let i = 0; i < unit[0].length && n > 0; i++) { let p = ''; for (let j = 0; j < unit[1].length && n > 0; j++) { p = digit[n % 10] + unit[1][j] + p; n = Math.floor(n / 10); } s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s; } return s.replace(/(零.)*零元/, '元') .replace(/(零.)+/g, '零') .replace(/^整$/, '零元整'); };

    数字转化为中文数字

    export const intToChinese = (value) => { const str = String(value); const len = str.length-1; const idxs = ['','十','百','千','万','十','百','千','亿','十','百','千','万','十','百','千','亿']; const num = ['零','一','二','三','四','五','六','七','八','九']; return str.replace(/([1-9]|0+)/g, ( $, $1, idx, full) => { let pos = 0; if($1[0] !== '0'){ pos = len-idx; if(idx == 0 && $1[0] == 1 && idxs[len-idx] == '十'){ return idxs[len-idx]; } return num[$1[0]] + idxs[len-idx]; } else { let left = len - idx; let right = len - idx + $1.length; if(Math.floor(right / 4) - Math.floor(left / 4) > 0){ pos = left - left % 4; } if( pos ){ return idxs[pos] + num[$1[0]]; } else if( idx + $1.length >= len ){ return ''; }else { return num[$1[0]] } } }); }

    5. 操作存储

    存储loalStorage

    export const loalStorageSet = (key, value) => { if (!key) return; if (typeof value !== 'string') { value = JSON.stringify(value); } window.localStorage.setItem(key, value); };

    获取localStorage

    export const loalStorageGet = (key) => { if (!key) return; return window.localStorage.getItem(key); };

    删除localStorage

    export const loalStorageRemove = (key) => { if (!key) return; window.localStorage.removeItem(key); };

    存储sessionStorage

    export const sessionStorageSet = (key, value) => { if (!key) return; if (typeof value !== 'string') { value = JSON.stringify(value); } window.sessionStorage.setItem(key, value) };

    获取sessionStorage

    export const sessionStorageGet = (key) => { if (!key) return; return window.sessionStorage.getItem(key) };

    删除sessionStorage

    export const sessionStorageRemove = (key) => { if (!key) return; window.sessionStorage.removeItem(key) };

    6. 操作cookie

    设置cookie

    export const setCookie = (key, value, expire) => { const d = new Date(); d.setDate(d.getDate() + expire); document.cookie = `${key}=${value};expires=${d.toUTCString()}` };

    读取cookie

    export const getCookie = (key) => { const cookieStr = unescape(document.cookie); const arr = cookieStr.split('; '); let cookieValue = ''; for (let i = 0; i < arr.length; i++) { const temp = arr[i].split('='); if (temp[0] === key) { cookieValue = temp[1]; break } } return cookieValue };

    删除cookie

    export const delCookie = (key) => { document.cookie = `${encodeURIComponent(key)}=;expires=${new Date()}` };

    7. 格式校验

    校验身份证号码

    export const checkCardNo = (value) => { let reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/; return reg.test(value); };

    校验是否包含中文

    export const haveCNChars => (value) => { return /[\u4e00-\u9fa5]/.test(value); }

    校验是否为中国大陆的邮政编码

    export const isPostCode = (value) => { return /^[1-9][0-9]{5}$/.test(value.toString()); }

    校验是否为IPv6地址

    export const isIPv6 = (str) => { return Boolean(str.match(/:/g)?str.match(/:/g).length<=7:false && /::/.test(str)?/^([\da-f]{1,4}(:|::)){1,6}[\da-f]{1,4}$/i.test(str):/^([\da-f]{1,4}:){7}[\da-f]{1,4}$/i.test(str)); }

    校验是否为邮箱地址

    export const isEmail = (value) { return /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value); }

    校验是否为中国大陆手机号

    export const isTel = (value) => { return /^1[3,4,5,6,7,8,9][0-9]{9}$/.test(value.toString()); }

    校验是否包含emoji表情

    export const isEmojiCharacter = (value) => { value = String(value); for (let i = 0; i < value.length; i++) { const hs = value.charCodeAt(i); if (0xd800 <= hs && hs <= 0xdbff) { if (value.length > 1) { const ls = value.charCodeAt(i + 1); const uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000; if (0x1d000 <= uc && uc <= 0x1f77f) { return true; } } } else if (value.length > 1) { const ls = value.charCodeAt(i + 1); if (ls == 0x20e3) { return true; } } else { if (0x2100 <= hs && hs <= 0x27ff) { return true; } else if (0x2B05 <= hs && hs <= 0x2b07) { return true; } else if (0x2934 <= hs && hs <= 0x2935) { return true; } else if (0x3297 <= hs && hs <= 0x3299) { return true; } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) { return true; } } } return false; }

    8. 操作URL

    获取URL参数列表

    export const GetRequest = () => { let url = location.search; const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 后面的字符串取出来 const paramsArr = paramsStr.split('&'); // 将字符串以 & 分割后存到数组中 let paramsObj = {}; // 将 params 存到对象中 paramsArr.forEach(param => { if (/=/.test(param)) { // 处理有 value 的参数 let [key, val] = param.split('='); // 分割 key 和 value val = decodeURIComponent(val); // 解码 val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字 if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则添加一个值 paramsObj[key] = [].concat(paramsObj[key], val); } else { // 如果对象没有这个 key,创建 key 并设置值 paramsObj[key] = val; } } else { // 处理没有 value 的参数 paramsObj[param] = true; } }) return paramsObj; };

    检测URL是否有效

    export const getUrlState = (URL) => { let xmlhttp = new ActiveXObject("microsoft.xmlhttp"); xmlhttp.Open("GET", URL, false); try { xmlhttp.Send(); } catch (e) { } finally { let result = xmlhttp.responseText; if (result) { if (xmlhttp.Status == 200) { return true; } else { return false; } } else { return false; } } }

    键值对拼接成URL参数

    export const params2Url = (obj) => { let params = [] for (let key in obj) { params.push(`${key}=${obj[key]}`); } return encodeURIComponent(params.join('&')) }

    修改URL中的参数

    export const replaceParamVal => (paramName, replaceWith) { const oUrl = location.href.toString(); const re = eval('/('+ paramName+'=)([^&]*)/gi'); location.href = oUrl.replace(re,paramName+'='+replaceWith); return location.href; }

    删除URL中指定参数

    export const funcUrlDel = (name) => { const baseUrl = location.origin + location.pathname + "?"; const query = location.search.substr(1); if (query.indexOf(name) > -1) { const obj = {}; const arr = query.split("&"); for (let i = 0; i < arr.length; i++) { arr[i] = arr[i].split("="); obj[arr[i][0]] = arr[i][1]; } delete obj[name]; return baseUrl + JSON.stringify(obj).replace(/[\"\{\}]/g,"").replace(/\:/g,"=").replace(/\,/g,"&"); } }

    9. 设备判断

    判断是移动还是PC设备

    export const isMobile = () => { if ((navigator.userAgent.match(/(iPhone|iPod|Android|ios|iOS|iPad|Backerry|WebOS|Symbian|Windows Phone|Phone)/i))) { return 'mobile'; } return 'desktop'; }

    判断是否是苹果还是安卓移动设备

    export const isAppleMobileDevice = () => { let reg = /iphone|ipod|ipad|Macintosh/i; return reg.test(navigator.userAgent.toLowerCase()); }

    判断是否是安卓移动设备

    export const isAndroidMobileDevice = () => { return /android/i.test(navigator.userAgent.toLowerCase()); }

    判断是Windows还是Mac系统

    export const osType = () => { const agent = navigator.userAgent.toLowerCase(); const isMac = /macintosh|mac os x/i.test(navigator.userAgent); const isWindows = agent.indexOf("win64") >= 0 || agent.indexOf("wow64") >= 0 || agent.indexOf("win32") >= 0 || agent.indexOf("wow32") >= 0; if (isWindows) { return "windows"; } if(isMac){ return "mac"; } }

    判断是否是微信/QQ内置浏览器

    export const broswer = () => { const ua = navigator.userAgent.toLowerCase(); if (ua.match(/MicroMessenger/i) == "micromessenger") { return "weixin"; } else if (ua.match(/QQ/i) == "qq") { return "QQ"; } return false; }

    浏览器型号和版本

    export const getExplorerInfo = () => { let t = navigator.userAgent.toLowerCase(); return 0 <= t.indexOf("msie") ? { //ie < 11 type: "IE", version: Number(t.match(/msie ([\d]+)/)[1]) } : !!t.match(/trident\/.+?rv:(([\d.]+))/) ? { // ie 11 type: "IE", version: 11 } : 0 <= t.indexOf("edge") ? { type: "Edge", version: Number(t.match(/edge\/([\d]+)/)[1]) } : 0 <= t.indexOf("firefox") ? { type: "Firefox", version: Number(t.match(/firefox\/([\d]+)/)[1]) } : 0 <= t.indexOf("chrome") ? { type: "Chrome", version: Number(t.match(/chrome\/([\d]+)/)[1]) } : 0 <= t.indexOf("opera") ? { type: "Opera", version: Number(t.match(/opera.([\d]+)/)[1]) } : 0 <= t.indexOf("Safari") ? { type: "Safari", version: Number(t.match(/version\/([\d]+)/)[1]) } : { type: t, version: -1 } }

    10. 浏览器操作

    滚动到页面顶部

    export const scrollToTop = () => { const height = document.documentElement.scrollTop || document.body.scrollTop; if (height > 0) { window.requestAnimationFrame(scrollToTop); window.scrollTo(0, height - height / 8); } }

    滚动到页面底部

    export const scrollToBottom = () => { window.scrollTo(0, document.documentElement.clientHeight); }

    滚动到指定元素区域

    export const smoothScroll = (element) => { document.querySelector(element).scrollIntoView({ behavior: 'smooth' }); };

    获取可视窗口高度

    export const getClientHeight = () => { let clientHeight = 0; if (document.body.clientHeight && document.documentElement.clientHeight) { clientHeight = (document.body.clientHeight < document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight; } else { clientHeight = (document.body.clientHeight > document.documentElement.clientHeight) ? document.body.clientHeight : document.documentElement.clientHeight; } return clientHeight; }

    获取可视窗口宽度

    export const getPageViewWidth = () => { return (document.compatMode == "BackCompat" ? document.body : document.documentElement).clientWidth; }

    打开浏览器全屏

    export const toFullScreen = () => { let element = document.body; if (element.requestFullscreen) { element.requestFullscreen() } else if (element.mozRequestFullScreen) { element.mozRequestFullScreen() } else if (element.msRequestFullscreen) { element.msRequestFullscreen() } else if (element.webkitRequestFullscreen) { element.webkitRequestFullScreen() } }

    退出浏览器全屏

    export const exitFullscreen = () => { if (document.exitFullscreen) { document.exitFullscreen() } else if (document.msExitFullscreen) { document.msExitFullscreen() } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen() } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen() } }

    11. 时间操作

    当前时间

    export const nowTime = () => { const now = new Date(); const year = now.getFullYear(); const month = now.getMonth(); const date = now.getDate() >= 10 ? now.getDate() : ('0' + now.getDate()); const hour = now.getHours() >= 10 ? now.getHours() : ('0' + now.getHours()); const miu = now.getMinutes() >= 10 ? now.getMinutes() : ('0' + now.getMinutes()); const sec = now.getSeconds() >= 10 ? now.getSeconds() : ('0' + now.getSeconds()); return +year + "年" + (month + 1) + "月" + date + "日 " + hour + ":" + miu + ":" + sec; }

    格式化时间

    export const dateFormater = (formater, time) => { let date = time ? new Date(time) : new Date(), Y = date.getFullYear() + '', M = date.getMonth() + 1, D = date.getDate(), H = date.getHours(), m = date.getMinutes(), s = date.getSeconds(); return formater.replace(/YYYY|yyyy/g, Y) .replace(/YY|yy/g, Y.substr(2, 2)) .replace(/MM/g,(M<10 ? '0' : '') + M) .replace(/DD/g,(D<10 ? '0' : '') + D) .replace(/HH|hh/g,(H<10 ? '0' : '') + H) .replace(/mm/g,(m<10 ? '0' : '') + m) .replace(/ss/g,(s<10 ? '0' : '') + s) } // dateFormater('YYYY-MM-DD HH:mm:ss') // dateFormater('YYYYMMDDHHmmss')

    12. JavaScript操作

    阻止冒泡事件

    export const stopPropagation = (e) => { e = e || window.event; if(e.stopPropagation) { // W3C阻止冒泡方法 e.stopPropagation(); } else { e.cancelBubble = true; // IE阻止冒泡方法 } }

    防抖函数

    export const debounce = (fn, wait) => { let timer = null; return function() { let context = this, args = arguments; if (timer) { clearTimeout(timer); timer = null; } timer = setTimeout(() => { fn.apply(context, args); }, wait); }; }

    节流函数

    export const throttle = (fn, delay) => { let curTime = Date.now(); return function() { let context = this, args = arguments, nowTime = Date.now(); if (nowTime - curTime >= delay) { curTime = Date.now(); return fn.apply(context, args); } }; }

    数据类型判断

    export const getType = (value) => { if (value === null) { return value + ""; } // 判断数据是引用类型的情况 if (typeof value === "object") { let valueClass = Object.prototype.toString.call(value), type = valueClass.split(" ")[1].split(""); type.pop(); return type.join("").toLowerCase(); } else { // 判断数据是基本数据类型的情况和函数的情况 return typeof value; } }

    对象深拷贝

    export const deepClone = (obj, hash = new WeakMap()) => { // 日期对象直接返回一个新的日期对象 if (obj instanceof Date){ return new Date(obj); } //正则对象直接返回一个新的正则对象 if (obj instanceof RegExp){ return new RegExp(obj); } //如果循环引用,就用 weakMap 来解决 if (hash.has(obj)){ return hash.get(obj); } // 获取对象所有自身属性的描述 let allDesc = Object.getOwnPropertyDescriptors(obj); // 遍历传入参数所有键的特性 let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc) hash.set(obj, cloneObj) for (let key of Reflect.ownKeys(obj)) { if(typeof obj[key] === 'object' && obj[key] !== null){ cloneObj[key] = deepClone(obj[key], hash); } else { cloneObj[key] = obj[key]; } } return cloneObj

    maps vs. sets data structure

    maps vs. sets data structure

    The way in which data is structured plays a vital role in our ability to efficiently perform certain operations on data, or to solve certain problems in relation to the data. For example, you can delete any item from a doubly-linked list in constant time, whereas that could take linear time if the list is represented as an array. Similarly, searching for the presence of a key in an array of keys can be done more efficiently in logarithmic time when the array is sorted, as opposed to when it is not sorted. Some very popular programming languages like Java and Python provide lots of useful data structure implementations out of the box, whereas the ubiquitous JavaScript programming language appears to be pretty lean in that regard. However, like most programming languages, JavaScript ships with some very basic data types — such as arrays, strings, objects, sets, maps, etc.

    Keyed collections

    Prior to the ECMAScript 2015 specification updates (popularly known as ES6), JavaScript provided Array objects as the only standard, inbuilt indexed collections — although there were other exotic objects such as the arguments and String objects, which behaved like arrays with special handling for integer index property keys, usually referred to as array-like objects, but were not really indexed collections. Starting with ES2015, a handful of new standard inbuilt types have been added to JavaScript, such as: Symbol Promise Proxy A number of typed array objects were also added, which, just like arrays, are also indexed collections themselves. In addition to these, a new category known as keyed collections has also been added to the language, with these inbuilt object types: Map Set WeakMap WeakSet Just as the name implies, every element (known as an entry) in a keyed collection can be identified by some kind of key, such that the keys in the collection are distinct — meaning that every key maps exactly to one entry in the collection. If you are familiar with hash tables, then you may have already inferred their usefulness here in ensuring that the average access time is sublinear on the number of elements in the collection. In this post, we’ll take a peek at how we can use JavaScript’s Map and Set objects to efficiently solve problems. Before we jump right in, let’s consider a sample problem. Below is a sample problem:
    💡 Contains Duplicates Given an array of integers nums, return true if any element appears at least twice in the array, and return false if every element is distinct.
    Pause for a moment and try solving this problem on your own, before you proceed. If the nums array was sorted, will that simplify the solution? Now, here is a working solution to the problem: function hasDuplicates(nums) { // 1. Sort the array in-place (sorting makes it easier) nums.sort((a, b) => a - b); if (nums.length > 1) { // 2. Loop through the sorted array until a duplicate is found for (let i = 1, len = nums.length; i < len; i++) { // If a duplicate is found, return immediately if (nums[i] == nums[i - 1]) return true; } } // 3. If it ever gets here, no duplicate was found return false; } There is no doubt that this solution works, for the given constraints of our problem. The reasoning behind why it should work is quite straightforward — if the array of integers is already sorted, then it is possible to check in a single pass whether or not two consecutive, equal integers exist in the array. Since there isn’t any guarantee that the array of integers will already be sorted, the solution first tries to sort the array, before checking for duplicate integers. Let’s analyze our solution. The running time of the above solution will grow in a linearithmic fashion as the size of the input array grows. While this isn’t a bad thing, it’s not so great either because, even for a pre-sorted array, it would still take a significant amount of time to process, as a lot of time is spent trying to sort the array first. The solution also uses Array.prototype.sort to sort the input array in-place — modifying the original input array as a result. Hence, no additional memory is required for the sort. It is important to note that, if the problem required that the original order of the input array remain unchanged, then a copy of the input array must be made before using this solution. This is tantamount to the use of additional memory that will grow in linear fashion as the size of the input array grows. Now, whether this is an acceptable solution or not is subject to a number of factors — including but not limited to: The constraints on the problem, such as the maximum size of the problem’s input The constraints on computational resources, such as the machine’s available memory Acceptable trade-offs, such as accepting the use of auxiliary space if that will potentially improve the running time, etc. If we are certain that the array of integers might not already be sorted, and we also don’t mind using some auxiliary space — provided we can get a faster running time — then this solution is not the best. As we progress, we will soon see that we can actually come up with a solution whose running time grows linearly, rather than linearithmically, with the size of the input.

    Defining and understanding Map objects

    We can summarize the ECMAScript 2015 specification definition of a Map object as follows: It is a collection of key/value pairs where both the keys and values may be arbitrary ECMAScript language values It is an ordered collection, which means that the insertion order of its elements matters and is followed when iterating the collection Keys in the collection are distinct or unique, and may only occur in one key/value pair within the Map’s collection Every key in the collection may occur only once with respect to the ECMAScript SameValueZero comparison algorithm That means any valid JavaScript value — both primitive values and object references, including unseemly values like NaN and undefined — can be used as a key in a Map object collection.

    Making equality comparisons with SameValueZero

    To determine whether a key already exists in the Map object collection — in other words, ensuring that keys are distinct — the ECMAScript SameValueZero comparison algorithm is used. We use this comparison algorithm because, if one of the listed algorithms were used: Strict Equality comparison algorithm: this would make it impossible to determine whether a key of value NaN already exists in the collection, since NaN === NaN always evaluates to false SameValue comparison algorithm: this makes it possible to determine whether a key of value NaN already exists in the collection, but the keys +0 and -0 are different keys and will be treated as such, despite that +0 === -0 always evaluates to true The SameValueZero comparison algorithm, however, behaves like the SameValue comparison algorithm, except that it considers both +0 and -0 to be the same key. If the SameValueZero comparison algorithm were to be implemented as a JavaScript function, it would look like this: function SameValueZero(x, y) { return x === y || (Number.isNaN(x) && Number.isNaN(y)); }

    What are Map entries?

    Each key/value pair contained in a Map object collection is usually referred to as an entry object, or entry. An entry object is usually represented using a two-element array — more like a tuple in most other programming languages — whose first element is the key and whose second element is the value. The type definition for a generic Map object entry should look like this (in TypeScript): type MapEntry<Key, Value> = [Key, Value]; That said, you can use JavaScript syntax, such as a destructuring assignment, on a Map object entry like you would with an array, as demonstrated in the following for...of loop example: /** * Iterating over entries of `Map` object using a * `for...of` loop — assuming that `map` has been * defined already as a `Map` object. */ for (const [key, value] of map) { console.log(key, value); } Both Map and Set objects inherit an entries() method from their corresponding constructors’ prototype objects. This entries() method returns an iterator for all of the entries contained in the collection with respect to their insertion order. For Map objects, however, the iterator returned by the entries() method also serves as the default iterator of the collection.

    Creating a Map object in JavaScript

    At the time of this article’s publication, the only way to create a Map object is by invoking the global Map constructor function. The constructor function must be invoked with the new keyword — otherwise, a TypeError will be thrown. When the Map constructor function is invoked without arguments, an empty Map object of 0 size is returned. // Throws a`TypeError` — when invoked without `new` keyword const throwTypeErrorMap = Map(); // Creates an empty `Map` object of 0 `size` const mapA = new Map(); // Omitting the parentheses — when invoked without arguments // Also creates an empty `Map` object of 0 `size` const mapB = new Map; console.log(mapA.size); // 0 console.log(mapB.size); // 0 The Map constructor function can also be invoked with an optional iterable argument. When specified, iterable must be a JavaScript object that: properly implements the iterable protocol — many inbuilt JavaScript objects implement this protocol, such as Array, String, and Set, as well as Map returns an iterator object that produces a two-element, array-like (entry) object whose first element is a value that will be used as a Map key, and whose second element is the value to associate with that key If the iterable argument does not meet these two requirements, a TypeError will be thrown — the only exception being when iterable is the value null or undefined, in which case the effect is the same as calling the Map constructor function without any argument, and an empty Map object of 0 size is created. Let’s pay more attention to the second requirement stated above. It is obvious that a new Map object cannot be created from a string primitive, even though String objects are iterable objects themselves. // Map from String — throws a `TypeError` const throwTypeErrorMap = new Map("programming"); When we create a new Map object from another iterable object, an empty Map object is first created, and then the following steps are taken for each entry object produced by the iterator object, which is returned by the iterable: Extract the first and second elements from the entry object as key and value, respectively Check if an entry with key already exists in the Map object collection using SameValueZero comparison If it exists, update the entry’s current value to value If it does not exist, append a new entry to the end of the Map object collection with that key and value (if the key is 0, change it to +0 before appending a new entry to the collection) const pairs = [[1, 3], [3, 3], [4, 2], [2, 2]]; // (1) Map from Array or Set // Here a set is created from the pairs array and // used to create the map. However, the map can also // be created directly from the pairs array. const mapA = new Map(new Set(pairs)); console.log(mapA.size); // 4 console.log(…mapA); // [1, 3] [3, 3] [4, 2] [2, 2] // (2) Map from Map // New map contains all the items of the original map // However, both maps are entirely different objects. // Think of it as creating a clone of a map. const mapB = new Map(mapA); console.log(…mapA); // [1, 3] [3, 3] [4, 2] [2, 2] console.log(…mapB); // [1, 3] [3, 3] [4, 2] [2, 2] console.log(mapA === mapB); // false console.log(mapA.size === mapB.size); // true // (3) Map from Object // In ES6, the Object.entries() method was added, // and it returns an array of entries representing // key/value pairs for every key in an object. const mapC = new Map(Object.entries({ language: “JavaScript”, hello: “world” })); console.log(mapC.size); // 2 console.log(…mapC); // [“language”, “JavaScript”] [“hello”, “world”] Now that we are able to create new Map objects, let’s go ahead to explore their instance properties and methods.

    Map object instance properties and methods

    Checking the size

    We’ve already seen the size property in action a couple of times. Just as the name implies, sizereturns the number of entries in the Map object at any instant. It might interest you to know that the size property is an accessor property and not a data property. Also, it only has a get accessor function, and not a set accessor function. That’s the reason why its value cannot be overridden by an assignment operation. Whenever you access the size property of a Map object, its get accessor function will be invoked, which basically counts and returns the number of elements (entries) currently in the Map object.

    Looking up a key

    There are several cases where it is sufficient to know only whether or not an entry with a particular key is present in a Map object. Every Map object will originally have a has() method — which can be called to assert whether or not an entry with a specified key is present in the Map object. The has() method returns a boolean value — true if the specified key is present, and false otherwise. const M = new Map(Object.entries({ language: "JavaScript", hello: "world" })); console.log(M.has("hello")); // true console.log(M.has("Hello")); // false console.log(M.has("language")); // true console.log(M.has("world")); // false Beyond checking whether a key exists in a Map object, being able to read the value of the entry associated with that key is also very important. As such, every Map object initially has a get() method for this purpose. When the get() method is called with a key for which no entry exists, it returns undefined. const M = new Map(Object.entries({ language: "JavaScript", hello: "world" })); console.log(M.get("hello")); // "world" console.log(M.get("Hello")); // undefined console.log(M.get("language")); // "JavaScript" console.log(M.get("world")); // undefined Although the get() method returns undefined for nonexistent keys, it should not be relied upon when checking for the existence of a key in a Map collection because it’s also possible for a key in the collection to have a value of undefined. The most accurate way to determine the existence of a key in the collection is to use the has() method.

    Adding, updating, and removing entries

    The ability to add, update, or remove one or more entries from a Map object is essential, and every Map object will have set(), delete(), and clear() methods. The set() method takes a JavaScript value as its argument and will append that value to the end of the Set object, provided it isn’t already in the Set object. If the specified value is already in the Set object, it is ignored. The add() method returns the same Set object with the added value, making it amenable to method chaining, or the process of invoking multiple add() calls at once. The delete() method, on the other hand, will remove the entry associated with the specified key from the Map object — provided there is such an entry in the Map object. If an entry is actually removed from the Map object as a result of this delete operation, it returns true; otherwise it returns false. It might be useful in some cases to completely remove all of the entries in a given Map object. While this can be achieved by making multiple delete() calls to the Map object, obviously it will make more sense if this is done in a single method call. This is exactly what the clear() method does. Calling the clear() method empties the Map object and returns undefined. // Convert object to map const M = new Map(Object.entries({ language: "JavaScript" })); console.log(M.size); // 1 console.log(...M); // ["language", "JavaScript"] // (1) Add and update some map entries M.set("year", 1991); M.set("language", "Python"); console.log(M.size); // 2 console.log(...M); // \["language", "Python"\] ["year", 1991] // (2) Add or update several values at once (using chaining) M.set("version", 3) .set("year", 2000) .set("version", "2.0"); console.log(M.size); // 3 console.log(...M); // \["language", "Python"\] ["year", 2000] ["version", "2.0"] // Delete some entries from the map console.log(M.delete("Year")); // false console.log(M.delete("year")); // true console.log(M.delete("year")); // false console.log(M.delete("version")); // true console.log(M.size); // 1 console.log(...M); // ["language", "JavaScript"] // Empty the map M.clear(); console.log(M.size); // 0

    Iterating the collection

    One other thing we might want to do with a Map object is view the keys, values, or entries that are in it. You can loop through each entry in a Map object (in insertion order) using the for...of loop. This is because every iterable has a Symbol.iterator() method that returns its default iterator — which is responsible for producing the sequence of values for the loop. Besides the for...of loop we looked at earlier, the same sequence of values returned by the default iterator is what the spread operator (...), the yield* statement, and destructuring assignment are based on. We’ve already seen the entries() method, which returns an iterator for all the entries in a Map object with respect to their insertion order. As stated earlier, the iterator returned by the entries() method also serves as the default iterator of a Map object. That said, the two for...of loops shown in the following code snippet are the same and will produce the exact same sequence of values: const M = new Map([[1, 3], [3, 3], [4, 2], [2, 2]]); // (a) Iteration using the default iterator ([Symbol.iterator]) for (const [key, value] of M) { console.log(key, value); } // (b) Iteration using the `entries()` iterator for (const [key, value] of M.entries()) { console.log(key, value); } It is important to note that an iterable object can provide other iterators besides the default iterator provided by its [Symbol.iterator] method. This holds true for most inbuilt iterables in JavaScript, including Map objects. In fact, every Map object originally has three methods that return iterators, namely: entries() keys() values() The keys() method, as the name implies, returns an iterator that yields the keys associated with each entry of the Map object (in insertion order). The values() method returns an iterator that yields the values associated with each entry of the Map object. The following code snippet demonstrates a couple of ways we can leverage the iterable behavior of a Map object to access the values or keys of each element in it. const M = new Map([[1, 3], [3, 3], [4, 2], [2, 2]]); // Using the spread operator (...) to pass values // in the Map object as function arguments. console.log(...M.values()); // 3 3 2 2 // Using the spread operator in building an array // with the unique keys of the Map object. const arr = [...M.keys()]; console.log(arr); // [1, 3, 4, 2] console.log(arr[0]); // 1 console.log(arr[3]); // 2 console.log(arr.length); // 4 // Using destructuring assignment with a `Map` object // to extract the first, second and remaining keys. const [first, second, ...remainingKeys] = M.keys(); console.log(first); // 1 console.log(second); // 3 console.log(remainingKeys); // [4, 2] console.log(remainingKeys.length); // 2 // Iteration using a for...of loop // to read all the keys in the collection. for (const key of M.keys()) { console.log(key); } // 1 // 3 // 4 // 2

    Iterating Map objects with the forEach() method

    We’ve been able to explore quite a number of ways in which we can iterate over a Map object. However, there remains one more very useful iteration method — the forEach() method. Just as with arrays, the forEach() method of a Map object accepts a callback function as its first argument, which is triggered for each entry of the Map object. The forEach() method also accepts an optional second argument, which represents the this value that will be used when executing the callback function. The forEach() callback function is called with three arguments for every entry of the Map object: The first argument is the value associated with the current entry in the iteration The second argument is the key associated with the current entry in the iteration The third argument is the Map object itself const M = new Map([[1, 4], [3, 5], [4, 0], [2, 2]]); M.forEach(function _callback(value, key, map) { console.log([...map]); const replacement = this[value]; if (replacement) map.set(key, replacement); else if (Number.isInteger(value)) map.delete(key); }, "hello"); console.log([...M]); // [[1, 4], [3, 5], [4, 0], [2, 2]] // [[1, "o"], [3, 5], [4, 0], [2, 2]] // [[1, "o"], [4, 0], [2, 2]] // [[1, "o"], [4, "h"], [2, 2]] // [[1, "o"], [4, "h"], [2, "l"]] To be clear, the forEach() method call in the previous code snippet results in the following _callback() calls: _callback.call("hello", 1, 4, M); _callback.call("hello", 3, 5, M); _callback.call("hello", 4, 0, M); _callback.call("hello", 2, 2, M);

    What is a JavaScript Set object?

    A Set object is an ordered collection of unique JavaScript values. For every Set object, there exists the following invariants: It is an ordered collection: The insertion order of its elements matters, and is followed when iterating the collection Values in the collection are distinct or unique: Every value may occur only once in the collection with respect to the ECMAScript SameValueZero comparison algorithm Any valid JavaScript value can be contained in the collection — both primitive values and object references, including unseemly values like NaN and undefined.

    Maps vs. Sets

    Since we’ve already explored Map objects in the previous section, let’s look at how they compare with Set objects before we continue.
    Set objectsMap objects
    one-dimensional collections: they store only unique valuestwo-dimensional collections: they store records as key/value pairs, and each key is unique in the collection
    Both key and value point to the same value or reference for every entryBoth key and value point to the same value or reference for every entry
    The default iterator ([Symbol.iterator]) of a Set object is the one returned from its values() methodThe default iterator is obtained from the entries() method
    set() and get() methods are not defined in the Set.prototype object; the Set.prototype object defines an add () methodThe set() and get() methods are defined in the Set.prototype object
    As we progress in our exploration of JavaScript Set objects, we will find out more ways in which Set objects differ from Map objects and some ways in which they are similar.

    Creating a Set object

    Just as with Map objects, the only way to create a Set object is by invoking the global Set constructor function. The constructor function must be invoked with the new keyword — otherwise, a TypeError will be thrown. When the Set constructor function is invoked without arguments, an empty Set object of 0 size is returned. // Throws a `TypeError` — when invoked without `new` keyword const throwTypeErrorSet = Set(); // Creates an empty `Set` object of 0 `size` const setA = new Set(); // Omitting the parentheses — when invoked without arguments // Also creates an empty `Set` object of 0 `size` const setB = new Set; console.log(setA.size); // 0 console.log(setB.size); // 0 The Set constructor function can also be invoked with an optional iterable argument. When specified, iterable must be a JavaScript object that properly implements the iterable protocol. Many inbuilt JavaScript objects implement this protocol — such as Array, String, and Map, as well as Set — which means that these are all valid objects and can be passed to the Set constructor function as the iterable argument. If the iterable is the value null or undefined, then the effect is the same as calling the Set constructor function without any argument — an empty Set object of 0 size will be created. Otherwise, a TypeError will be thrown for any other iterable value that does not properly implement the iterable protocol. Unlike with Map objects, creating a new Set object from another iterable object has the effect of de-duping, i.e., eliminating redundant duplicate values from the values yielded by the internal iterator of the iterable object. This is because of one important attribute of a Set object, which is that it must contain only distinct, discrete values. // (1) Set from String // Set contains all the unique characters of the string const testString = "programming"; const uniqueChars = new Set(testString); console.log(testString.length); // 11 console.log(uniqueChars.size); // 8 console.log(...uniqueChars); // p r o g a m i n // (2) Set from Array // Set contains all the distinct elements of the array const integers = [1,1,1,3,3,4,3,2,4,2]; const distinctIntegers = new Set(integers); console.log(integers.length); // 10 console.log(distinctIntegers.size); // 4 console.log(...distinctIntegers); // 1 3 4 2 // (3) Set from Set // New set contains all the items of the original set // However, both sets are entirely different objects. // Think of it as creating a clone of a set. const setA = new Set([1,1,1,3,3,4,3,2,4,2]); const setB = new Set(setA); console.log(...setA); // 1 3 4 2 console.log(...setB); // 1 3 4 2 console.log(setA === setB); // false console.log(setA.size === setB.size); // true Let’s take another shot at our sample problem from earlier and employ what we’ve learned so far about Set objects. This time, we will be creating a new Set object from the nums array, containing only distinct integers (no duplicates). We can then determine whether the nums array contains duplicates by comparing the size of the Set object with the length of the nums array. Here is what the new solution looks like: function hasDuplicates(nums) { // Create a new set from `nums` containing only its distinct // integers (i.e de-duplicate the `nums` array). const distinct = new Set(nums); // If the size of the distinct set matches the length of the // nums array, then there are no duplicates, and vice-versa. return distinct.size != nums.length; } In using a Set object, we have been able to implement a solution whose running time is guaranteed to grow linearly with the size of the input array, even though it will require some additional memory to perform. When it comes to storing unique items in memory, a set of items with duplicates will use less space than one without duplicates. In other words, the worst case scenario in terms of memory usage happens when the set contains only unique items and no duplicates — in that case, the amount of space used matches the number of items.

    Set object instance properties and methods

    Checking the size

    Just as with Map objects, the size property returns the number of values in a Set object at any instant. Again, the size property of the Set.prototype object is an accessor property, not a data property. Set also only has a get accessor function and not a set accessor function — hence, it cannot be overridden by an assignment operation. Whenever you access the size property of a Set object, its get accessor function will be invoked, and it will count and return the number of elements (values) that are currently in the Set object.

    Checking whether a value is present

    Every Set object will originally have a has() method that can be called to assert whether or not an element with a specified value is present in the Set object. Like with Map objects, the has() method returns a boolean value — true if the specified value is present, and false otherwise. const uniqueChars = new Set("programming"); console.log(...uniqueChars); // p r o g a m i n console.log(uniqueChars.has("p")); // true console.log(uniqueChars.has("A")); // false console.log(uniqueChars.has("a")); // true console.log(uniqueChars.has("t")); // false Since Set objects are one-dimensional (storing only unique values), it is impractical for them to have a get() method, unlike with Map objects. As a result, the Set.prototype object does not define a get() method.

    Adding and removing values

    It is very important to be able to add or remove one or more values from a Set object, and every Set object will initially have add(), delete(), and clear() methods. The add() method takes a JavaScript value as its argument, and will append that value to the end of the Set object, provided that it isn’t already in the Set object. If the specified value is already in the Set object, it is ignored. The add() method returns the same Set object, with the added value, which makes it amenable to method chaining, or the familiar process of invoking multiple add() calls at once. Just like with Map objects, the delete() method of a Set object will remove the element associated with the specified value from the Set object, provided that such an element is present in the Set object. If an element is actually removed from the Set object as a result of this delete operation, it returns true; otherwise it returns false. Also, a call to the clear() method empties the Set object and returns undefined. // Create new set of integers const integers = new Set([1,1,1,3,3,4,3,2,4,2]); console.log(integers.size); // 4 console.log(...integers); // 1 3 4 2 // Add some values to the set integers.add(5); integers.add(1); console.log(integers.size); // 5 console.log(...integers); // 1 3 4 2 5 // Add several values at once (using chaining) integers.add(7).add(2).add(9); console.log(integers.size); // 7 console.log(...integers); // 1 3 4 2 5 7 9 // Delete some values from the set console.log(integers.delete(3)); // true console.log(integers.delete(8)); // false console.log(integers.delete(3)); // false console.log(integers.delete(1)); // true console.log(integers.size); // 5 console.log(...integers); // 4 2 5 7 9 // Empty the set integers.clear(); console.log(integers.size); // 0 Now that we’ve learned a few more things we can do with Set objects, let’s return to our previous solution to our original sample problem and see if we can optimize it even further. (As you might have rightly guessed, we can.) A careful examination of our previous solution will show that it’s doing a little too much. It always considers every integer in the input array, adding them to the Set object (just like using the add() method multiple times) and then checking its size, which counts and returns the number of elements in the Set object by going through each element. The problem with this solution is that it isn’t conservative. It is very possible that a duplicate integer might be found by considering the first few integers in the array, and so the act of considering the remaining integers in the array becomes redundant. To optimize this solution, we can decide to be lazy about adding integers to the Set object, and only continue as long as we haven’t encountered an integer that has already been added to the Set object. Here is what the optimized solution looks like: function hasDuplicates(nums) { // 1. Create an empty set to hold distinct integers const distinct = new Set(); // 2. Loop through the integers until a duplicate is found for (const int of nums) { // 2a. If a duplicate is found, return immediately if (distinct.has(int)) return true; // 2b. Otherwise, add the integer to the distinct set distinct.add(int); } // 3. If it ever gets here, no duplicate was found return false; }

    Iterating keyed collections

    It is often necessary to have a view into the values that are contained in a Set object. This is very attainable with arrays or indexed collections — hence, we can easily access the element of an array (arr), at some index (i), using the property access bracket notation (arr[i]). Unfortunately, this kind of element access is not directly possible with Set() objects because Set objects are keyed collections. However, just like with arrays and other iterables, you can loop through the values for each element in a Set object (in insertion order) using the for...of loop, or you could use the sequence of values it produces with the spread operator (...), the yield* statement, or destructuring assignment. The following code snippet demonstrates a couple of ways we can leverage the iterable behavior of a Set object to access the values of each element in it. const integers = new Set([1,1,1,3,3,4,3,2,4,2]); // Using the spread operator (...) to pass values // in the Set object as function arguments. console.log(...integers); // 1 3 4 2 // Using the spread operator in building an array // with the unique values from the Set object. const arr = [...integers]; console.log(arr); // [1, 3, 4, 2] console.log(arr[0]); // 1 console.log(arr[3]); // 2 console.log(arr.length); // 4 // Using destructuring assignment with a `Set` object const [first, second, ...remainingIntegers] = integers; console.log(first); // 1 console.log(second); // 3 console.log(remainingIntegers); // [4, 2] console.log(remainingIntegers.length); // 2 // Iteration using a `for...of` loop for (const integer of integers) { console.log(integer); } // 1 // 3 // 4 // 2 Just like with Map objects, every Set object originally has three methods that return iterators — values(), keys(), and entries(). The values() method, as the name implies, returns a new iterator that yields the values for each element in the Set object (in insertion order). The iterator returned by the values() method yields the exact same sequence of values as the default iterator returned by the [Symbol.iterator] method. For iteration purposes, the keys() method of a Set object behaves exactly like the values() method, and they can be used interchangeably. In fact, the values, keys, and [Symbol.iterator] properties of a Set object all point to the same value (function) initially. Hence, the following for...of loops will log the exact same sequence of values. const integers = new Set([1,1,1,3,3,4,3,2,4,2]); // (a) Iteration using the default iterator (`[Symbol.iterator]`) for (const integer of integers) { console.log(integer); } // (b) Iteration using the `values()` iterator for (const integer of integers.values()) { console.log(integer); } // (c) Iteration using the `keys()` iterator for (const integer of integers.keys()) { console.log(integer); } Some basic set operations can be implemented by iterating over one or more Set objects. For example, the following code snippet shows how to implement the union and intersection set operations. function union(setA, setB) { const setUnion = new Set(setA); for (const value of setB) { setUnion.add(value); } return setUnion; } function intersection(setA, setB) { const setIntersection = new Set(); for (const value of setB) { if (setA.has(value)) { setIntersection.add(value); } } return setIntersection; } Just as with Map objects, Set objects also have a forEach() method with a similar call signature. However, to account for the one-dimensional nature of Set objects, the forEach() callback function is called with three arguments: The first argument is the value for the current element in the iteration The second argument is always the same as the first argument The third argument is the Set object itself const S = new Set([1,1,1,3,3,4,3,2,4,2]); S.forEach(function _callback(value, _, set) { console.log([...set]); const replacement = this[value]; if (replacement) set.add(${value}${replacement}); if (Number.isInteger(value)) set.delete(value); }, "hello"); // [1, 3, 4, 2] // [3, 4, 2, '1e'] // [4, 2, '1e', '3l'] // [2, '1e', '3l', '4o'] // ['1e', '3l', '4o', '2l'] // ['1e', '3l', '4o', '2l'] // ['1e', '3l', '4o', '2l'] // ['1e', '3l', '4o', '2l'] console.log(...S); // 1e 3l 4o 2l To be clear, the forEach() method call in the previous code snippet results in the following _callback() calls: _callback.call("hello", 1, 1, S); _callback.call("hello", 3, 3, S); _callback.call("hello", 4, 4, S); _callback.call("hello", 2, 2, S); _callback.call("hello", '1e', '1e', S); _callback.call("hello", '3l', '3l', S); _callback.call("hello", '4o', '4o', S); _callback.call("hello", '2l', '2l', S);

    Accidental undefined — what does it mean?

    When the Set constructor function is called without any argument, you already know that it creates an empty Set object. The same, however, does not hold true for the add() method. When the add() method of a Set object is called without any argument, it actually adds an element to the collection with a value of undefined, if it does not already exist. In other words, for a given Set object S, S.add() is exactly the same as S.add(undefined). This is what I’d like to refer to as an accidental undefined — because it might not be intended. You might have already inferred the behavior of the has() and delete() methods when they’re called without any argument. As with the add() method, calling these methods without any argument is exactly the same as calling them with undefined as the first argument. Hence, for a given Set object S, S.has() checks whether undefined exists as a value in the Set object, while S.delete() removes the value undefined from the collection, if it exists. // Creates an empty set object const S = new Set(); // Add some items to the set object S.add(5); S.add("hello"); console.log(...S); // 5 'hello' // Adds undefined to the set object S.add(); console.log(...S); // 5 'hello' undefined console.log(S.has(5)); // true console.log(S.has("world")); // false // Logs `true` because `undefined` exists in the set console.log(S.has()); // true // Logs `true` because `undefined` was removed from the set console.log(S.delete()); // true // Logs `false` because `undefined` does not exist in the set console.log(S.has()); // false That said, always be sure to explicitly call the add(), delete(), and has() methods of a Set object with at least one argument to avoid dealing with an accidental undefined value.

    Removing duplicates from Set objects

    Before we finish this section on JavaScript Set objects, let’s see how we can solve a modified version of the sample problem from before, using all we’ve learned so far.
    💡 Contains Duplicates (2) Given an array of integers nums, return the number of elements that appear at least twice in the array, and return 0 if every element is distinct.
    Pause for a moment and try solving this problem on your own, before you proceed. The solution could be a little tricky — how can you ensure a duplicate integer is not counted more than once? Now, here is a working solution to the problem: function countDuplicates(nums) { // Create an empty set for distinct integers // (i.e integers appearing only once) const distinct = new Set(); // Create an empty set for duplicate integers const duplicates = new Set(); // Create a variable to keep track of the duplicates count let count = 0; // Loop through the integers while counting duplicates for (const int of nums) { // If duplicate integer is found (it has already been counted), // continue with the iteration to the next integer. if (duplicates.has(int)) continue; if (distinct.delete(int)) { // If integer was successfully deleted from the `distinct` set, // that means it has been seen once before. Hence add it, to // the `duplicates` set and increment `count`. duplicates.add(int); count++; } else { // Integer is being seen for the first time and should be added // to the `distinct` set. distinct.add(int); } } // Finally, return the duplicates count return count; }

    Map or set?

    So far, we have been able to explore JavaScript Map and Set objects in detail. But in addition to that, we also need to be able to determine when it is sufficient to use one instead of the other in solving problems. Earlier on, we saw that Set objects are one-dimensional collections, whereas Map objects are two-dimensional. That could serve as a cue in determining which one is best suited for a particular problem. In other words, a Map object should be used over a Set object in cases where additional information is needed aside from just the key. Most times, that additional information is required to make decisions or to compute the final output of the program. To further demonstrate this, let’s consider another popular problem.
    💡Two Sum Given an array of integers and a specific target, return true if two numbers exist in the array that add up to the target, and false otherwise.
    If the array were to be sorted, then it would be possible to come up with a linear time solution to this problem without any need for auxiliary space. But since there is a possibility that the array is not already sorted, we need to use a Set object to provide some auxiliary space where we can solve the problem in linear time without taking on the expensive task of sorting the array first. function twoSum(nums, target) { // 1. Create an empty set for complements // (i.e complement = target - num) const complements = new Set(); // 2. Loop through integers until a complement is found for (const num of nums) { // 2a. If a complement is found, return immediately if (complements.has(target - num)) return true; // 2b. Otherwise, add the integer to the complements set complements.add(num); } // 3. If it ever gets here, no complement was found return false; } Here, we are required to return true if there are two numbers that sum up to the specified target, and false otherwise. As such, we are only interested in the numbers themselves, which is why we only need to use one Set object to solve the problem. Now, let’s instead say we modify the problem to return the array indices of the two numbers. We would be better off using a Map object. That’s because, in addition to the numbers themselves, we are now also interested in their corresponding indices in the array — both of which cannot be contained in a singular Set object. function twoSum(nums, target) { // 1. Create an empty map for integers against indices // (i.e Map<integer, index>) const indices = new Map(); // 2. Loop through integers until a complement is found for (let i = 0, len = nums.length; i < len; i++) { // 2a. Compute the complement of the current integer const complement = target - nums[i]; // 2b. If the complement already exists in the map, // get the complement index from the indices map and // return early ([complement index, current index]) if (indices.has(complement)) { return [indices.get(complement), i]; } // 2c. Otherwise, add the current integer and index // to the indices map indices.set(nums[i], i); } // 3. If it ever gets here, no complement was found return null; }

    Other Map and Set uses

    Map and Set objects can be very useful when modeling compound data structures to solve certain kinds of problems. In general, whenever you need to be able to look up or check for the existence of an item with an average access time that is sublinear on the number of available items (approximately constant time), you should consider using a Set or Map object.

    Data caching with Map objects

    When modeling data structures for the purpose of caching data, a Map object can be used as a lookup table to check for the existence of a key in the cache before performing get() or put() operations. Usually, cache implementations include some kind of strategy for removing items from the cache in order to free up space — the most popular cache eviction strategies being: least frequently used (LFU) and least recently used (LRU). Consider the get() operation of an LRU cache, for example: the expectation is to be able to fetch a record from the cache using its cache key in approximately constant time, and in the process, the record gets ranked as the most recently used record because it is the most recently accessed. In order to meet the above stated expectation, a fast lookup of the cache key is required — and that is where a Map object or any other form of hash table shines. To maintain a proper ranking of recently accessed records, a priority queue can be used. However, most implementations use a doubly-linked list instead, since it is capable of both removing the record from its current position in the list and re-inserting it to the head position of the list, all in constant time. A minimalist implementation blueprint of a typical LRU cache could look somewhat like this (the full implementation details have been omitted for brevity): interface ICache<K, V> { get: (key: K) => V; put: (key: K, data: V) => void; } class LRUCache<K, V> implements ICache<K, V> { /** * A DLL is used to maintain the order of the items * in the cache according to how recently they were * used (accessed or added). * * Using a DLL makes it possible to remove an item * from any position in the list (in constant time). */ protected list = new DoublyLinkedList<V>(); /** * A Map object is used as a lookup table to check * for the existence of a key in the cache with an * average access time that is sublinear on the * number of cache items (approximately constant * time). */ protected table = new Map<K, V>(); /** * @param size {number} The number of items that * can be stored in the cache. */ constructor(protected size: number) {} get(key: K): V {} put(key: K, data: V): void {} }

    Graphical representation with map and set

    Most connectivity problems are better solved when the problem data is represented as a graph, using either of two forms of graph representation: Adjacency Matrix Adjacency List For most problems, an adjacency list representation should suffice — and for that, Map and Set objects can be used. Most adjacency list implementations use arrays and/or linked lists, but it is also possible to use Map and Set objects. The Map object stores each vertex in the graph as its keys, with their corresponding list of neighboring vertices in Set objects as its values. A typical implementation of an undirected graph represented as an Adjacency List (using Map and Set objects) should look somewhat like this: interface IGraph<V> { addVertex: (vertex: V) => void; addEdge: (fromVertex: V, toVertex: V) => void; removeVertex: (vertex: V) => void; removeEdge: (fromVertex: V, toVertex: V) => void; } class UndirectedGraph<V> implements IGraph<V> { /** * A Map object is used to map each vertex in the * graph to a set of vertices that are connected * to it. */ protected list = new Map<V, Set<V>>(); addVertex(vertex: V): void { if (!this.list.has(vertex)) { // An array can be used to represent the set // of vertices — but in this implementation, // a Set object is used instead. this.list.set(vertex, new Set<V>()); } } addEdge(fromVertex: V, toVertex: V): void { this.addVertex(fromVertex); this.addVertex(toVertex); (this.list.get(fromVertex) as Set<V>).add(toVertex); (this.list.get(toVertex) as Set<V>).add(fromVertex); } removeVertex(vertex: V): void { if (this.list.has(vertex)) { for (const toVertex of this.list.get(vertex) as Set<V>) { this.removeEdge(vertex, toVertex); } this.list.delete(vertex); } } removeEdge(fromVertex: V, toVertex: V): void { if (this.list.has(fromVertex) && this.list.has(toVertex)) { (this.list.get(fromVertex) as Set<V>).delete(toVertex); (this.list.get(toVertex) as Set<V>).delete(fromVertex); } } }

    Disjoint-sets and dynamic connectivity

    A niche of connectivity problems can be solved using special data structures called disjoint-sets. A disjoint-set is used to maintain a set of elements (nodes) that are partitioned into a number of non-overlapping (disjointed) subsets, also known as connected components. Disjoint-sets are structured in such a way as to efficiently perform two operations, namely: find: checks for the subset an element or node belongs to union: merges two subsets into a single subset; can also be used for detecting cycles in undirected graphs The following Disjoint-Set implementation uses a Map object to maintain its non-overlapping subsets (the implementation is detailed): interface IDisjointSet<T> { find: (node: T) => T; union: (nodeA: T, nodeB: T) => void; } class DisjointSet<T> implements IDisjointSet<T> { /** * A Map object is used to link each node to the * root of its corresponding connected component * subset (using a disjoint-set data structure). */ protected subsets = new Map<T, T | number>(); addNode(node: T): void { if (!this.subsets.has(node)) { this.subsets.set(node, -1); } } find(node: T): T { let root = node; while (true) { const parent = this.subsets.get(root) as T; if (!this.subsets.has(parent)) { if (node !== root) { this.subsets.set(node, root); } return root; } root = parent; } } union(nodeA: T, nodeB: T): void { const rootA = this.find(nodeA); const rootB = this.find(nodeB); const sizeA = this.subsets.get(rootA) as number; const sizeB = this.subsets.get(rootB) as number; const sizeAB = sizeA + sizeB; if (sizeA < sizeB) { this.subsets.set(rootB, rootA); this.subsets.set(rootA, sizeAB); } else { this.subsets.set(rootA, rootB); this.subsets.set(rootB, sizeAB); } } isConnected(nodeA: T, nodeB: T): boolean { return this.find(nodeA) === this.find(nodeB); } }

    Conclusion

    Maps and sets in JavaScript can come in very handy for quite a number of applications and when trying to solve a number of problems efficiently — especially when efficient lookups are required. In fact, they are specialized hash table implementations for JavaScript, akin to the HashMap and HashSet types in Java — albeit, with some subtle differences. For safe garbage collection guarantees, consider using the even more restrictive WeakMap and WeakSet keyed collections.

    LogRocket: Debug JavaScript errors more easily by understanding the context

    Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them. LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exactly what the user did that led to an error. LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

    Introduction to Map Data Structure

    https://flaviocopes.com/javascript-data-structures-map/ A Map is a collection of key — value pairs, similar to an object. It stores the key — value pairs in the insertion order. We can create a Map by passing an iterable object whose elements are in the form of key — value (Eg. [ [1,”one”], [2,”two”] ] ), or you can create an empty Map, then insert entries.

    Why we need Map if we have Object s

    1. A Map is similar to Object, but any value can be used as key in maps, but keys in objects are only Strings and Symbols 2. The key — value pairs in Map maintains the insertion order, whereas Object don’t. 3. You can get the size of the Map, but we don’t have a built-in method to get size in Object (but we can do it manually). 4. Maps are iterable, whereas an Object is not iterable by-default. 5. Maps have additional methods not available to normal objects

    Methods in Maps

    Map cheatsheet Example: Different Ways to create maps 2. Map methods Let’s create simple Map: // creating a map var fruits = new Map(); fruits.set('🍎', "Apple"); fruits.set('🍋', "Mango"); fruits; //{"🍎" => "Apple", "🍋" => "Mango"} Map has a property size which returns the current Map size (total number of entries). // size fruits.size; // 2 set(, value) → Set the value for the key in the Map and returns the Map. If the key is already present in the map, then the value is overwritten. // set(key , value) method fruits.set( '🍇', "Grapes"); fruits; // {"🍎" => "Apple", "🍋" => "Mango", "🍇" => "Grapes"} get() → Returns the value associated to the key, or returns undefined if there is no key on the Map that matches the passed key. // get(key) fruits.get('🍇'); // GRAPES. fruits.get('🍊'); //undefined. delete() → Delete the entry matching the key and returns true. If the key is not found in the map, then it returns false. // delete(key) fruits.delete('🍊') //false fruits.delete('🍇'); // true has() → Returns true if the map has the key provided, else return false. //HAS(key) fruits.has('🍇'); // true fruits.has('🍊'); //false keys() → Returns a new iterator that contains the keys in insertion order. //keys fruits.keys() // MapIterator {"🍎", "🍋"} values() → Returns a new iterator that contains the values in insertion order. // values fruits.values() // MapIterator {"Apple", "Mango"} entries() → Returns an iterator which has an array of [-value] pair in insertion order. //entries --> returns key value pair fruits.entries() // MapIterator {"🍎" => "Apple", "🍋" => "Mango"} clear() → Delete all key-value pairs from the Map. // clear fruits.clear(); // deletes all elementfruits; // Map(0) {}

    Things you should know about Map

    You can use any value (object or function or primitive ) as a key in the Map . Map uses the SameValueZero algorithm. It is similar to strict equality (===) but the difference is that NaN is considered equal to NaN (i.e, NaN === NaN → true. In normal JS, this is not true. In this case NaN can be used as key and we don’t have any duplicate NaN). var map = new Map()var obj = {}; var arr = []; var nan = NaN; var fun = function() {}map.set(obj, "object"); map.set(arr , "array"); map.set(fun, "function"); map.set(nan, "Wrong number"); map.keys(); // MapIterator {{…}, Array(0), ƒ, NaN}map.values(); // MapIterator {"object", "array", "function","Wrong number"}

    Iterating through Map

    Using for…of // creating a map var fruits = new Map(); fruits.set('🍎', "Apple"); fruits.set('🍋', "Mango"); fruits; //{"🍎" => "Apple", "🍋" => "Mango"} Method 1: for(var [key, val] of fruits) { console.log(key, value);} 🍎 Apple 🍋 Mango Method 4 --> using entriesfor (var [key, val] of fruits.entries()) { console.log(key , val); } 🍎 Apple 🍋 Mango Method 2 --> using keys for(var key of fruits.keys()) { console.log(key, fruits.get(key)); } 🍎 Apple 🍋 Mango Method 3 --> using valuesfor(var val of fruits.values()) { console.log(val); }Apple Mango

    Iterables

    Iterable objects are objects that can be iterated over with for..of. Technically, iterables must implement the Symbol.iterator method.

    Iterating Over a String

    You can use a for..of loop to iterate over the elements of a string: for (const x of "W3Schools") { // code block to be executed }

    Iterating Over an Array

    You can use a for..of loop to iterate over the elements of an Array: for (const x of [1,2,3,4,5] { // code block to be executed }

    JavaScript Iterators

    The iterator protocol defines how to produce a sequence of values from an object. An object becomes an iterator when it implements a next() method. The next() method must return an object with two properties: value (the next value) done (true or false) value The value returned by the iterator (Can be omitted if done is true) done true if the iterator has completed false if the iterator has produced a new value

    Home Made Iterable

    This iterable returns never ending: 10,20,30,40,.... Everytime next() is called: // Home Made Iterable function myNumbers() { let n = 0; return { next: function() { n += 10; return {value:n, done:false}; } }; } // Create Iterable const n = myNumbers(); n.next(); // Returns 10 n.next(); // Returns 20 n.next(); // Returns 30 The problem with a home made iterable: It does not support the JavaScript for..of statement. A JavaScript iterable is an object that has a Symbol.iterator. The Symbol.iterator is a function that returns a next() function. An iterable can be iterated over with the code: for (const x of iterable) { } // Create an Object myNumbers = {}; // Make it Iterable myNumbers[Symbol.iterator] = function() { let n = 0; done = false; return { next() { n += 10; if (n == 100) {done = true} return {value:n, done:done}; } }; } Now you can use for..of for (const num of myNumbers) { // Any Code Here } The Symbol.iterator method is called automatically by for..of. But we can also do it "manually": let iterator = myNumbers[Symbol.iterator](); while (true) { const result = iterator.next(); if (result.done) break; // Any Code Here }

    use this to return object content

    Think place it at end of file $("k").click(function() { alert($(this).text()) });

    DOM manipulation

    <body> <div> <span>Hello</span> <span style="display: none;">Bye</span> </div> </body> const body = document.body body.append("Hello world", "Bye") const div = document.querySelector("div") div.innerText = "Hello world" div.innerHtml = "<strong>Hello world</strong>" body.append(div) const spanHI = document.querySelector("#hi”) const spanBye = document.querySelector("#bye”) console.log(spanHi.getAttribute("title")) console.log(spanHi.setAttribute("title", "sassssd")) spanHi.id= "sassssd" spanHi.title= "sassssd" spanHi.removeAttribute("id") console.log(spanHi.title) console.log(spanHi.id) spanBye.remove() div.append(spanBye) spanHi.dataset.longerName = "long" spanHi.classList.toggle("long", true) spanHi.style.color = "red" spanHi.style.backgroundColor = "red"

    load function after document loaded

    <body onkeypress="chkKey()" onload="docLoaded()"> function docLoaded() { let script = document.createElement('script'); script.src = 'app.js'; document.body.appendChild(script); } app.js: window.scrollTo(0,(document.body.scrollHeight)); $("k").click(function() { alert($(this).text()) });

    Get values from the "GET" parameters

    var url_string = location.href; var url_string = "https://williamkpchan.github.io/LibDocs/Random%20Charts.html?okvalue=12&shatvalue=120" paramsArray = url_string.split('?') // use ? to seperate paramsArray.shift() let params = {}; for (let i = 0; i < paramsArray.length; ++i) { let param = paramsArray[i].split('=', 2); if (param.length !== 2) continue; params[param[0]] = decodeURIComponent(param[1].replace(/\+/g, " ")); } params var url_string = location.href; var url_string = "https://williamkpchan.github.io/LibDocs/Random%20Charts.html&okvalue=12" paramsArray = url_string.split('?') // note this has changed to array paramsArray.shift() if(paramsArray.length!=0){ param = paramsArray[0].split('=')[1]; // paramsArray is still array } else{ initStkCode() } var url_string = location.href; paramsArray = url_string.split('?') // html?00981 paramsArray.shift() if(paramsArray.length!=0){ thecode = paramsArray[0]; // paramsArray is still array } else{ if (localStorage.getItem("randomcode") === null) { localStorage.randomcode = "07500"; } else{ thecode = localStorage.getItem("randomcode"); } }

    Redirect Methods

    You can redirect a web page via JavaScript using a number of methods. We will quickly list them and conclude with the recommended one. In JavaScript, window.location or simply location object is used to get information about the location of the current web page (document) and also to modify it. The following is a list of possible ways that can be used as a JavaScript redirect: // Sets the new location of the current window. window.location = "https://www.example.com"; // Sets the new href (URL) for the current window. window.location.href = "https://www.example.com"; // Assigns a new URL to the current window. window.location.assign("https://www.example.com"); // Replaces the location of the current window with the new one. window.location.replace("https://www.example.com"); // Sets the location of the current window itself. self.location = "https://www.example.com"; // Sets the location of the topmost window of the current window. top.location = "https://www.example.com"; Though the above lines of JS code accomplish a similar job in terms of redirection, they have slight differences in their usage. For example, if you use top.location redirect within an iframe, it will force the main window to be redirected. Another point to keep in mind is that location.replace() replaces the current document by moving it from the history, hence making it unavailable via the Back button of the browser. It is better to know your alternatives but if you want a cross-browser compliant JavaScript redirect script, our recommendation will be to use the following in your projects: window.location.href = "https://www.example.com"; Simply insert your target URL that you want to redirect to in the above code. You can also check this page to read more about how window.location works. Now, let’s continue with our examples.

    JavaScript Redirect: Redirect the Page on Page Load

    In order to redirect the user to another website immediately after your website is opened, you can use the following code at the top of your page, within the <head> element. Or, if you are using a separate .js file, put the following code into that file and remember to link to it from the head of your page. <script> window.location.href = "https://www.example.com"; </script> Simply replace the example URL with the one you want to redirect to. Note that, with this type of redirection, the visitors will not see your web page at all and be redirected to the target URL instantly.

    JavaScript Redirect: Redirect the Page After a Certain Period

    In order to redirect the user to another website after a certain time passes, you can use the following code: <script> setTimeout(function() { window.location.href = "https://www.example.com"; }, 3000); </script> The above function will redirect the page 3 seconds after it fully loads. You can change 3000 (3 x 1000 in milliseconds) as you wish.

    JavaScript Redirect: Redirect the Page After an Event or User Action

    Sometimes, you may want to send the user to another page after a certain event or action takes place, such as a button click, an option selection, a layout change, a form submission, a file upload, an image drag, a countdown timer expiration or things like that. In such cases, you can either use a condition check or assign an event to an element for performing the redirect. You can use the following two examples to give you a basic idea: <script> // Check if the condition is true and then redirect. if ( ... ) { window.location.href = "https://www.example.com"; } </script> The above code will do the redirection if the condition is true. <script> // onclick event is assigned to the #button element. document.getElementById("button").onclick = function() { window.location.href = "https://www.example.com"; }; </script> The above code will do the redirection when the user clicks the #button element. This is how JavaScript redirect basically works. We hope that the above examples will help you while handling your web page redirects.

    on "swiperight"

    <script src="https://code.jquery.com/mobile/1.5.0-alpha.1/jquery.mobile-1.5.0-alpha.1.min.js"></script> $( "div.box" ).on( "swiperight", handleRight ); $( "div.box" ).on( "swipeleft", handleLeft ); function handleRight( event ){ $(".box").append(" right") } function handleLeft( event ){ $(".box").append(" left") } $( "div.box" ).bind( "tap", tapHandler ); function tapHandler( event ){ $( event.target ).addClass( "tap" ); } $( "div.box" ).bind( "taphold", tapholdHandler ); function tapholdHandler( event ){ $( event.target ).addClass( "taphold" ); } $( "div.box" ).on( "swipe", swipeHandler ); function swipeHandler( event ){ $( event.target ).addClass( "swipe" ); }

    fetch a file

    fetch(urladdr) .then(x => x.text()) .then(function(response) { alert(response); }) // Note Fetch is based on async and await, use async theurl = 'https://web.ifzq.gtimg.cn/appstock/app/usfqkline/get?_var=kline_dayqfq¶m=' + '00700' + ',day,,,5,qfq'; getText(theurl); async function getText(urladdr) { let x = await fetch(urladdr); let y = await x.text(); document.getElementById("test").innerHTML = y; }

    给fetch添加功能

    简易版本

    代码 function createRequestWithTimeout(timeout = 3000) { return function(url, options) { return new Promise((resolve, reject) => { const timeoutId = setTimeout(() => { reject(new Error("Request timeout")); }, timeout); fetch(url, options) .then((response) => { clearTimeout(timeoutId); return response.json(); }) .then((response) => { clearTimeout(timeoutId); return resolve(response); }) .catch((error) => { clearTimeout(timeoutId); reject(error); }); }); }; } const request = createRequestWithTimeout(); function handle() { request("api/abc/abc", { method: "GET" }) .then((res) => { console.log(res); }) .catch((error) => { console.log(error); }); } 解析 定义一个名为createRequestWithTimeout的函数,它返回一个新的函数,这个返回的函数用于发起一个带有超时机制的HTTP请求。 1、createRequestWithTimeout函数接收一个可选参数timeout,默认值为3000毫秒(3秒)。 参数控制请求的超时时间。 2、返回的函数接收两个参数,url(请求的URL)和options(请求的选项,如请求方法、头部等)。 个函数返回一个Promise对象。 3、在返回的函数内部,首先使用setTimeout创建一个定时器,这个定时器会在timeout毫秒后触发。 如果在timeout时间内请求没有完成,定时器会调用reject方法,传递一个错误对象,错误信息为"Request timeout"。 4、使用fetch函数发起HTTP请求。 fetch函数接收url和options参数。 5、fetch返回的Promise被then方法处理。 第一个then处理响应的body,将其转换为JSON格式。 如果转换成功,它会调用resolve方法,传递解析后的数据。 6、如果在转换响应体为JSON时发生错误,或者在fetch请求过程中发生错误,catch方法会被调用,它会调用reject方法,传递错误信息。 7、在每个then和catch处理器中,都会调用clearTimeout来清除之前设置的超时定时器。 这样做是为了确保在请求成功完成或失败时,不会触发超时错误。 8、handle函数调用request函数发起请求,并处理成功和失败的情况。 成功时,它会打印响应数据;失败时,它会打印错误信息。 函数的目的是确保HTTP请求不会无限期地挂起,如果请求在指定的时间内没有完成,就会被中止,并且会通知调用者请求超时。 这在处理可能需要较长时间的网络请求时非常有用,可以避免用户界面冻结或资源浪费。

    升级版本

    代码 function createRequestWithTimeout(timeout = 3000) { return function(url, options) { return new Promise((resolve, reject) => { const abort = new AbortController(); options = options || {}; if (options.signal) options.signal.addEventListener("abort", () => { abort.abort(); }); options.signal = abort.signal; setTimeout(() => { reject(new Error("Request timeout")); abort.abort(); }, timeout); fetch(url, options) .then((response) => { return response.json(); }) .then((data) => { return resolve(data); }) .catch((error) => { reject(error); }); }); }; } const request = createRequestWithTimeout(); function handle() { request("api/abc/abc", { method: "GET" }) .then((res) => { console.log(res); }) .catch((error) => { console.log(error); }); } 解析 定义一个名为createRequestWithTimeout的函数,它返回一个异步函数,该函数可以发起一个带有超时机制的HTTP请求。 1、createRequestWithTimeout函数接受一个可选参数timeout,默认值为3000毫秒(3秒)。 参数定义请求的超时时间。 2、createRequestWithTimeout返回一个函数,该函数接受两个参数,url(请求的URL)和options(请求的选项,如请求方法、头部等)。 这个返回的函数返回一个Promise对象。 3、在返回的函数内部,首先创建一个AbortController实例abort。 AbortController是一个用于控制一个或多个Web请求的接口,它允许取消这些请求。 4、options参数被检查,如果它已经包含一个signal属性(即一个AbortSignal对象),则为该信号添加一个事件监听器。 这个监听器会在signal被中止时调用abort.abort(),从而中止fetch请求。 5、options的signal属性被设置为abort实例的signal属性,这样就可以在超时发生时通过abort.abort()来中止请求。 6、使用setTimeout设置一个定时器,如果在timeout毫秒后请求还没有完成,setTimeout的回调函数会被调用,它会拒绝Promise并中止请求。 7、使用fetch函数发起HTTP请求。 fetch函数接受url和options参数。 8、fetch返回的Promise被then方法处理。 第一个then处理响应的body,将其转换为JSON格式。 如果转换成功,它会调用resolve方法,传递解析后的数据。 9、如果在转换响应体为JSON时发生错误,或者在fetch请求过程中发生错误,catch方法会被调用,它会调用reject方法,传递错误信息。 10、handle函数调用request函数发起请求,并处理成功和失败的情况。 成功时,它会打印响应数据;失败时,它会打印错误信息。 createRequestWithTimeout函数的目的是确保HTTP请求不会无限期地挂起。 如果请求在指定的时间内没有完成,它会被中止,并且会通知调用者请求超时。 这对于防止长时间挂起的请求导致的性能问题非常有用。

    Hacking HTTP CORS

    https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS https://infosecwriteups.com/hacking-http-cors-from-inside-out-512cb125c528

    Same Origin Policy (SOP)

    Before we get to the CORS matter, it is essential to comprehend an underlying concept of web resources access protection. I’m talking about the Same Origin Policy, also known for the acronym SOP. As to avoid unauthorized use of resources by external parties, the browsers count on an origin-based restriction policy. Formally, the said external parties are identified by their origin (domain) and accessed through URLs. A document held by a given origin A will only be accessible by other documents from the SAME origin A. This rule is valid if the SOP is effectively in place (and depends on the browser implementation). This policy aims to reduce the chances of a possible attack vector. But let’s depict what an origin looks like. One origin could be understood as the tuple: <schema (or protocol)><hostname><port> So two URLs represent the same origin only if they share the same tuple. Examples of origin variations and categories for the URL `http://hacking.cors.com/mr_robots.txt`: Domain types differentiation Additionally, keep in mind that the SOP allows inter-origin HTTP requests with GET and POST methods. But it forbids inter-origin PUT and DELETE. Besides that, sending custom HTTP headers is permitted only in the context of inter-origin requests, being denied to foreigners.

    SOP variations

    There are some different types of Same Origin Policy. In practice, they are applied under particular rules given the technology in place. The primary SOP policy developed was towards the DOM (Document Object Model) access. It is a mechanism that handles JavaScript and other scripting languages’ ability to access DOM properties and methods across domains. The DOM access is based mainly on the `document.domain` DOM’s property state. But the same is not valid for the JavaScript’s XMLHttpRequest API, which does not take `document.domain` property into account. For now, don’t worry too much about these details. We should be back to this subject soon. So if we take SOP as a sandboxing concept, it becomes reasonable to have the same origin implementations for other web technologies as well. It is the case of cookies, Java, old-R.I.P Flash, and their respective SOP policy feature.

    HTTP CORS Fundamentals

    The SOP technology was certainly a considerable jump towards more secure web applications. But it applies the deny rule by default. The true nature of the World Wide Web is that pages could communicate with other resources all across the network. Web applications are meant to access external resources. So how do we relax the same-origin rules while maintaining the security access of restricted resources? You got it: CORS. In simple terms, Cross-Origin Resource Sharing allows the pages from a specific domain/origin to consume the resources from another domain/origin. The consent of who can access a resource is the resource’s owner (server) responsibility. The browser-server trust relationship takes form through a family of CORS HTTP Headers. In the average case, they are added to the HTTP requests and responses by the resource’s web server (like Nginx, Apache, IIS, etc.), by the application, or the browser. The CORS headers then instruct the soliciting browser whether or not to trust the origin and proceed with the response processing. Let’s take a breath here. Note that the browser fully trusts the response returned from the server. Keep this in mind.

    Simple Request

    In contrast to Preflight requests, there are simple ones. Simple requests are those who respect the following conditions: Simple requests composition When making asynchronous HTTP requests, we often use the already presented XMLHttpRequest or the new Fetch JavaScript APIs.

    Preflight HTTP Request

    Sometimes a preflight HTTP request is launched by the browser. It intents to query the server about what CORS attributes are authorized and supported by it. However, this does not change the trustiness relationship between server and browser. The preflight HTTP request (which takes the form of an HTTP OPTIONS request) results in an equally trusted HTTP response. The only difference resides in the headers, that indicate the browser how to proceed to get the intended cross-origin resource. Pre-request flight flow for deletion of avatar.org As we move to the hands-on sections of this article, this will get more palatable.

    CORS basic headers

    Achieving origin control by the CORS involves the following headers’ family: CORS headers family and their respective HTTP type The headers marked with YES at the “Used for Preflight HTTP ” column play crucial preflight functions. It goes from denoting which specific headers (Access-Control-Allow-Headers) and HTTP methods (Access-Control-Allow-Methods) are allowed, the maximum amount of seconds the browser should cache the Preflight request (Access-Control-Max-Age), request source (Origin), to the allowance (Access-Control-Allow-Credentials) of cookies to be sent by browsers in the actual request. In the overall context, the Access-Control-Allow-Origin (ACAO) stands as the most relevant header regarding cross-origin authorization. Through this header, the server is able to tell the browser which domains it should trust. This great power comes with significant responsibilities, though.

    Allowing too much is not cool at all

    It is clear to us that CORS is a useful way to extend SOP policies. However, we should take into account the impact of a full nonrestrictive rule. Let’s take the following statement: Access-Control-Allow-Origin: * The above header means that every origin could access the desired resource. This would be equivalent to the earlier configuration of older browsers before SOP was in place. But be aware of the other side of the story, as cautiously depicted by the application security literature.
    “Obviously there might be cases where a wildcard value for the Access-Control-Allow-Origin isn’t insecure. For instance, if a permissive policy is only used to provide content that doesn’t contain sensitive information.” The Browser Hacker’s Handbook 2nd Ed. — Chapter 4 Bypassing the Same Origin Policy
    You should be careful with the wildcards, though. Indeed, the recommended approach is make the access permission explicit for the authorized origins. If the server does not provide the CORS headers whatsoever, the browsers will assume the Same Origin Policy (SOP) posture.

    The Docker-based proposed scenario

    First, lets clone the `hacking-cors` repository so we can get this party started! $ git clone git@github.com:lvrosa/hacking-cors.git Tree directory representation of the hacking-cors docker project The above structure breaks down the docker containers and files that compose the server images. The `node_modules` directory (omitted from the `tree` command output above) is pushed to the `hacking-cors` repository as well. It has a short size. However, if you have any problems regarding JavaScript dependencies, please run the `npm` tool at the project root directory. $ cd hacking-cors; npm install It is also crucial to have `docker` and ` installed on your system. The docker-compose file uses version 3 format. My current versions for both dependencies are: Docker and Docker Compose versions

    Project structure

    We have two distinct docker projects. They are represented by their respective configuration Dockerfile at the root directory. Docker files respective to each web server Interesting files are at the `static` and `img` directories. They hold the resources that will eventually be solicited by other web pages. JavaScript files are under the `static` directory. You can open them in your favorite code editor and play around. The `img` directory from the Trusted Site stores the `owasp_bug.png` resource. In our experiment, this image resource will be requested by the Evil Site, which will then try to load it. The same applies to the `static/hello_script.js` file, but to execute/evaluate the script content, and not load an image.

    Docker images and network settings overview

    docker-compose.yml content Take a look at the `docker-compose.yml` file above. We can identify important things about the environment like: We’ll create two containers (namely `evil_site` and `trusted_site`) The containers are attached to the `cors_hack_net` bridged network interface The `cors_hack_net` interface determines the subnet by the CIDR 10.5.0.0/16 As a useful link to the containers’ network addresses, I’d recommend setting your static lookup table for hostnames file (`/etc/hosts`) to the following settings: /etc/hosts file mapping

    A glance at the Apache Server CORS rules

    ★ Identify the Trusted Site container’s name: docker-compose ps output ★ Log into the container: $ docker exec -it trusted_site /bin/bash ★ Dump the Apache `.htaccess` configuration file to the screen: .htaccess Apache CORS extension rules As highlighted in the picture above, the Apache Web Server will serve the ACAO (Access-Control-Allow-Origin) header when the file-matching rule applies. In other words, if the web browser requests an image (.gif, .png, .ico, etc.) or even a JavaScript .js file, the resource’s content will only be authorized to be loaded/consumed by the page if the origin matches `http://trustedsite.com`. Note that the `.htaccess` file is sourced at `htdocs` directory, thus impacting all the files under its substructure.

    Running the containerized environment

    To get these environment live, follow the steps: ★ Build the container from the root project directory $ docker-compose build — no-cache; (note the double minus before the no-cache argument) ★ Up the containers through `docker-compose` $ docker-compose up docker-compose up output If you run into any trouble with the docker environment, I suggest you clean it by killing and removing the current active docker images. Just ensure you don’t have other containers that should have their state saved before being killed. $ docker kill $(docker ps -a -q) $ docker rm $(docker ps -a -q) Well, I hope everything has been ok so far. Let’s take a look at the two created web servers. Open your browser and drive to the `http://trustedsite.com` and `http://evilsite.com`.

    Trusted Site

    Trusted Site Web Server menu

    Evil Site

    Evil Site Web Server Menu

    Playing with CORS rules using XHR and Fetch requests

    CORS rules for XHR requests

    The XMLHttpRequest Standard[11] defines an API that provides scripted client functionality for transferring data between a client and a server. Regarding its security aspects, we should be aware of some warning facts, as stated by the Browser Security Handbook, part2[12].
    “The set of security-relevant features provided by XMLHttpRequest, and not seen in other browser mechanisms, is as follows:
    The ability to specify an arbitrary HTTP request method (via the open() method), The ability to set custom HTTP headers on a request (via setRequestHeader()), The ability to read back full response headers (via getResponseHeader() and getAllResponseHeaders()),
    The ability to read back the full response body as a JavaScript string (via responseText property). Since all requests sent via XMLHttpRequest include a browser-maintained set of cookies for the target site and given that the mechanism provides a far greater ability to interact with server-side components than any other feature available to scripts, it is extremely important to build in proper security controls.”
    It’s essential to observe the following browser protections against origin tampering upon handling XHR requests. When trying to change/poison the `origin` header via setRequestHeader(), the original header is preserved. When trying to change/poison the additional headers (passed as arguments to the xhr.send()), the original header is preserved.

    CORS rules for Fetch requests

    “Numerous APIs provide the ability to fetch a resource, e.g. HTML’s img and script element, CSS’ cursor and list-style-image, the navigator.sendBeacon() and self.importScripts() JavaScript APIs. The Fetch Standard provides a unified architecture for these features so they are all consistent when it comes to various aspects of fetching, such as redirects and the CORS protocol.” — https://fetch.spec.whatwg.org/
    Although The Fetch Standard supersedes the `origin` element semantics (originally defined in The Web Origin Concept — RFC6454), the same effect of the XHR tampering protections applies here. When trying to change/poison the `origin` header via fetch() arguments, the original header is preserved.

    Understanding the requests cycle in practice

    Now that you already know the fundamentals of SOP, CORS, XHR and Fetch requests, we’re ready to play with the proposed scenario. Both Trusted Site and Evil Site pages have similar menus. Firstly, try the four requests options of the Trusted Site. Note that the requested resources, the OWASP bug image or the script that displays “All your base belong to us ;D”, are successfully loaded and consumed by the page. This is a classical case of local resources invoked by one page belonging to the same domain. The hello_script.js’ content executed after one same domain page request Now, let’s change the scope to the Evil Site. Open the `http://evilsite.com` website Bring up the Web Developer Tools window (press F12 in Firefox or Chrome) Click the anchor link associated with the OWASP image + JavaScript XHR Click the anchor link associated with the Alert script + JavaScript Fetch Get your focus on the Console tab from Web Developer Tools. We should be looking at something like the screen below. The third and fourth steps generate the messages from the screen above. They are transcripted below for accessibility purposes.
    Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://trustedsite.com/img/owasp_bug.png. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘http://trustedsite.com’). Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://trustedsite.com/static/hello_script.js. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘http://trustedsite.com’).
    From here, it’s possible to understand why the browser has prohibited the requested resource. Remember the Apache Server .htaccess configuration, which adds the ACAO (Access-Control-Allow-Origin) CORS header to specific HTTP responses (image files and .js scripts). Now, we are going to investigate the requests in more detail. Click the Network tab from the Web Developer Tools. Then, select the OPTIONS request for the `hello_script.js` resource. On the right side of the screen, you should see the following HTTP request and response. OPTIONS HTTP request and response for hello_script.js resource Take note of the `Origin` header from above. It reads `http://evilsite.com`. But if we dive into the `script_fetch.js` implementation of the Evil Site, something stands out about the `Origin` header. `evil_site_public_html/static/script_fetch.js` content Although we try to overlap the `Origin` header (line 7) with the authorized address of Trusted Site‘s domain — `http://trustedite.com`, the Fetch API implemented by the browser prevents this from taking effect. That’s why we see `http://evilsite.com` as `Origin` in the Web Developer Tools’ Network tab — HTTP OPTIONS request.

    Bypassing CORS through proxy interception (Manual)

    It’s been a long road so far. So if you made it here, it’s time to put some salt in the soup. The main principle behind the CORS (and policies like CSP — Content Security Policy) is the trust-based relationship between browser and web server. The web server instructs the web browser about which domains it can further trust. In practice, the HTTP security headers set this instruction. Now, let’s think from a malicious perspective. To bypass the CORS rules, the attacker has to intercept the server’s HTTP response, which contains the CORS ACAO (Access-Control-Allow-Origin) header. Secondly, he/she changes its value to reflect the attacker’s page origin or to allow arbitrary domains (using the character *). When it’s said “to intercept”, it can be a proxy server filtering the HTTP request-response cycle automatically (see the next section for more on this). Or a manual approach through a proxy tool like Burp Suite, as we will do right after.

    Setting up your snoopy proxy tool

    If you are already familiarized with proxy tools like ZAP, Burp Suite, feel free to move to the next section. Here we are going to use Burp Suite Community[14] from PortSwagger. Install the Burp Suite according to your platform/architecture and run it. ★ At the Options tab, edit the Interface column at the Proxy Listeners settings as below (“127.0.0.1:10001”): ★ At the same tab, set the Intercept Client Requests settings as following: ★ Still at the Options tab, set the Intercept Server Responses settings as following: ★ Ensure that the “Intercept is on” button from Intercept tab is active Finally, on your browser, you will configure it to pass the requests through our proxy. Note that the proxy is listening on port 10001. Here we have two configuration options. I usually set my proxies using the FoxyProxy extension[15]. But you can do it manually by the Network Settings[16] from your browser. My Firefox’s FoxyProxy burp proxy settings Ok, that’s all. We’re ready to go.

    Bypassing CORS by HTTP Response tampering

    ★ Open the Evil Site (`http://evilsite.com`) As previously observed, resources from the Trusted Site requested by the Evil Site are not authorized to be consumed by the corresponding page. It results from the fact that the CORS ACAO (Access-Control-Allow-Origin) header only allows the `http://trustedsite.com` domain. ★ Activate your Burp proxy at your browser ★ Click/request OWASP image resource via XHR Request Stop and look to the Burp Suite dialog respective to the HTTP Request ★ Proceed with the request without further edition by clicking in “Forward” ★ Stop at the HTTP Response which contains the CORS headers ★ Edit the CORS ACAO header value to `*` Submit the response to the browser by clicking in “Forward” ★ The protected resource (OWASP bug image) content is displayed (note the absence of the CORS error message):

    Hacking homework

    In the earlier scenario, we intercepted and tampered with one JavaScript XHR request via Burp proxy. One important aspect of this outside the box approach is to analyze the HTTP request-response cycle thoroughly. Which headers are demanded and what error messages you got at your browser console when they are missing or misconfigured. Now it’s time to let you apply by yourself the knowledge exposed ‘till here. The next section will also present some hints about the CORS bypassing for the Alert script + JavaScript FETCH combination. Since the sky’s the limit, feel free to try the bypassing against the remaining options from the Evil Site menu.

    Tips for bypassing the Alert script + JavaScript FETCH

    Besides changing the Access-Control-Allow-Origin header, you will also have to add the Access-Control-Allow-Headers in the HTTP OPTIONS request (use the Add button from the Burp request edit dialog). This is necessary because the client (the .js script which launches the XHR request) adds the headers `cache-control` and `pragma` in the subsequent GET request by default. So you will want to reflect this in the HTTP OPTIONS response. Remember, here we have a HTTP Preflight scenario (review the Preflight HTTP Request section when in doubts), where a HTTP OPTIONS request precedes the actual resource retrieval request. HTTP Options response edited to reflect the CORS headers for bypassing HTTP GET response from `hello_script.js` resource retrieval (note the ACAO CORS header) Successful CORS hacking get us the nice dialog above

    Automatic bypassing and other CORS interesting projects

    In the previous section, we saw how to bypass the CORS rules protection manually. However, this is not very efficient from a practical standpoint. One feasible way to automate the bypassing process is by deploying a proxy server like CORS Anywhere API. The proxy server will act as an intermediary, filtering the request and response headers to reflect the allow and deny rules specified at proxy configuration time. Please, refer to the project’s Github page[18] for more details and precautions when setting a proxy facing the web (be careful with open proxies, friend). You can test the live API here[19].

    Concluding remarks

    If you’ve got this far, congratulations. HTTP Headers by itself is a very vast CORStopic, as the protocol tries to evolve to get close to web applications reality. This reality becomes more and more pervasive, especially with the popularization of APIs through technologies like REST. The set of CORS headers are intricate and full of nuances. When implementing a solution that deals with inter-domain communication, pay attention to the common pitfalls that can arise. The final message about CORS and its weaknesses is that the trust between browser and application should be explicitly guaranteed by secure configurations. The right choice for which AJAX method and CORS headers to deploy will positively impact your APIs’ overall security. Remember our four proposed resource consumption scenarios. They are simple. Indeed, there are other options and combinations for resource sharing. But maybe (and I hope we got there) the theory and practice exposed here can be taken as a foundation to design more complex and secure by-default web applications.

    crossorigin="anonymous"

    script src="https://stackoverflow.com/foo.js" crossorigin="anonymous" The "anonymous" keyword means that there will be no exchange of user credentials via cookies, client-side SSL certificates or HTTP authentication example: <link crossorigin="anonymous" media="all" integrity="sha512-iwdBeEEuDZbd2aAEzZti+bkBYQ2UKC6VEAhVMLKq5cCJnyeWVpgVqtgd3scKeZ63wYQTUQegRZwFGKlWOyr5Ew==" rel="stylesheet" href="https://github.githubassets.com/assets/frameworks-8b074178412e0d96ddd9a004cd9b62f9.css" /> <script crossorigin="anonymous" defer="defer" integrity="sha512-CzeY4A6TiG4fGZSWZU8FxmzFFmcQFoPpArF0hkH0/J/S7UL4eed/LKEXMQXfTwiG5yEJBI+9BdKG8KQJNbhcIQ==" type="application/javascript" src="https://github.githubassets.com/assets/environment-0b3798e0.js"></script>

    array techinque

    months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"), monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),

    GlobalTimezone

    "US": -13:00 美国 "CA": -13:00 加拿大 "UK": -08:00 英国 "DE": -07:00 德国 "FR": -07:00 法国 "IT": -07:00 意大利 "PT": -08:00 葡萄牙 "ES": -07:00 西班牙 "CH": -07:00 瑞士 "AU": +03:00 澳大利亚 "NZ": +05:00 新西兰 "CN": +00:00 北京时间 "JP": +01:00"};//东京时间 function getGlobalTimezone(__stringArea) { return __stringArea in GlobalTimezone ? GlobalTimezone[__stringArea].replace(":", .") * 1 : 0; }

    connect SQL Server database from JavaScript in the browser

    There is no common way to connect to SQL Server database from JavaScript client, every browser has it’s own API and packages to connect to SQL Server. For example, in Windows operating system, Internet Explorer has a class name called ActiveXObject which is used to create instances of OLE Automation objects, and these objects help us to create an environment for SQL Driver connection. var connection = new ActiveXObject("ADODB.Connection") ; var connectionstring = "Data Source=<server>;Initial Catalog=<catalog>;User ID=<user>;Password=<password>;Provider=SQLOLEDB"; connection.Open(connectionstring); var rs = new ActiveXObject("ADODB.Recordset"); rs.Open("SELECT * FROM table", connection); rs.MoveFirst while(!rs.eof) { document.write(rs.fields(1)); rs.movenext; } rs.close; connection.close; It is not recommended to use JavaScript clients to access databases. Node.js provides us an environment to run JavaScript code outside the browser. It’s strongly recommended to use any command-line tool(CLI) like terminal, cmd to run following queries and commands. connect with SQL Server sqlcmd -S localhost -U SA -P "<password>" To create Node.js environment issue following command. npm init Express allows us to set up middlewares to respond to HTTP Requests. npm install express --save Microsoft SQL Server client give us functionality to connect with SQL server. npm install mssql --save To begin with Node.js part, we need to create our server file server.js in our local system. javascript // Requiring modules const express = require('express'); const app = express(); const mssql = require("mysql"); // Get request app.get('/', function(req, res) { // Config your database credential const config = { user: 'SA', password: 'Your_Password', server: 'localhost', database: 'geek' }; // Connect to your database mssql.connect(config, function(err) { // Create Request object to perform // query operation var request = new mssql.Request(); // Query to the database and get the records request.query('select * from student', function(err, records) { if (err) console.log(err) // Send records as a response // to browser res.send(records); }); }); }); var server = app.listen(5000, function() { console.log('Server is listening at port 5000...'); }); Run server.js file using the following command: node server.js After executing the above command, you will see the following output on your console: Server is listening at port 5000... Now hit the url http://localhost:5000/ in the local browser.

    Tips

    Flatten the array of the array

    This tip will help you to flatten a deeply nested array of arrays by using Infinity in flat. var array = [123, 500, [1, 2, [34, 56, 67, [234, 1245], 900]], 845, [30257]] //flatten array of array array.flat(Infinity) // output: // [123, 500, 1, 2, 34, 56, 67, 234, 1245, 900, 845, 30257]

    Easy Exchange Variables

    You probably swap the two variables using a third variable temp. But this tip will show you a new way to exchange variables using destructuring. //example 1 var a = 6; var b = 7; [a,b] = [b,a] console.log(a,b) // 7 6

    Sort Alphabetically

    Sorting is a common problem in programming and this tip will save your valuable time by writing a long code to sort a string alphabetically. //sort alphabeticallyfunction alphabetSort(arr) { return arr.sort((a, b) => a.localeCompare(b)); } let array = ["d", "c", "b", "a"] console.log(alphabetSort(array)) // ["a", "b", "c", "d"]


    Generate Range of Numbers

    Suppose you want to generate a number between a specific range. The first approach you will use is the loop. But this tip will save you valuable time by doing it the easy way. let Start = 10, End = 15; //Generating [...new Array(End + 1).keys()].slice(Start); // [10, 11.... 15] Array.from({length: End - Start + 1}, (_,i) => Start + i) // [10, 11.... 15]

    Shorten the Console log

    Tired of writing console.log() again and again? This tip will show how to shorter your console log and speed up your coding. var c = console.log.bind(document) c(455) c("hello world")

    Shortening an Array in an easy way

    This is an awesome tip for web developers to shorten an array in an easy way. You just need to use the length method by passing a number that denotes the new size of your array. let array = ["A", "B", "C", "D", "E", "F"] array.length = 2 console.log(array) // ["A", "B"]


    Use isNumber

    This tip will show how to check whether a value or variable holding a number ( integer, float and etc ) or not. function isNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n); } console.log(isNumber(900)) // true console.log(isNumber(23.98)) // true console.log(isNumber("JavaScript")) // false

    Use isString

    This useful tip will show you how to check whether a value or data is in string format or not. This comes in handy when you request data from the server and want to check the data type. const isString = value => typeof value === 'string'; isString('JavaScript'); // true isString(345); // false isString(true); // false

    Check Null

    In Programming, sometimes we need to check whether a result or data is null. const CheckNull= value => value === null || value === undefined; CheckNull(null) // true CheckNull() // true CheckNull(123) // false CheckNull("J") // false

    Merge Array into One

    This tip will be useful when you need to combine the two arrays of any size into one. You need to use the JavaScript concate method for this. //Example Code let arr1 = ["JavaScript", "Python", "C++"] let arr2 = ["Dart", "Java", "C#"] const mergeArr = arr1.concat(arr2) console.log(mergeArr) // ["JavaScript", "Python", "C++", "Dart", "Java", "C#"]

    Quick Calculate Performance

    This tip is personally used most to calculate the performance of my JavaScript program. const starttime = performance.now(); //some program const endtime = performance.now(); const totaltime = startTime - endTime console.log("function takes "+totaltime +" milisecond");

    Remove Duplicates

    You probably encounter an array with duplicate data and use a loop way to get rid of these duplicates. This tip will help you remove duplicates in an easy way without using any loop. const ReDuplicates = array => [...new Set(array)]; console.log(ReDuplicates([200,200,300,300,400,500,600,600])) // [200,300,400,600]

    Convert Number to Binary

    This tip is useful when you need to convert numbers into binary. Take a look at the example code below. var num = 200 console.log(num.toString(2)) // 11001000 num = 300 console.log(num.toString(2)) //100101100

    Character “e” for excessive zeros

    This is a time-saving tip for you. You can rid of writing a lot of zeros in JavaScript by replacing all of them with the character “e”. //normal way var num = 20000000 //good way var num2 = 2e7 console.log(num2) //20000000

    Make Array Empty

    This quick tip will save the time that you put to empty an array. I will show you the quick method to empty in an array using the JavaScript length method. let array = ["A", "B", "C", "D", "E", "F"] array.length=0 console.log(array) // []

    Final Thoughts

    I hope you find this article useful and fun to learn these tips. If you had a good JavaScript tip feel free to share it with other developers in response. Happy JavaScript Coding.

    Pre-fill form with local storage

    to create a single localStorage entry representing your saved values, rather than pollute LS with many entries for each field. function save() { const selects = document.querySelectorAll('select'); // select other element types // ... const selectValues = [...selects].map(select => select.value); const textValues = [...textInputs].map(textInput => textInput.value); const sliderValues = [...sliderInputs].map(sliderInput => sliderInput.value); const savedObj = { selectValues, textValues, sliderValues }; localStorage.savedFormValues = JSON.stringify(savedObj); }

    use .get or .post to collect file from url

    w3school HTTP Request .get, .post $("button").click(function(){ url= 'https://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?_var=kline_dayqfq¶m=hk00700,day,,,1000,qfq' $.get(url, function(data, status){ objdata = eval(data) keys = Object.keys(objdata) console.log(keys) $("#cvs").text(JSON.stringify(objdata.data)) ; }); }); // will be blocked $("button").click(function(){ $.post("demo_test.asp", function(data, status){ alert("Data: " + data + "\nStatus: " + status); }); }); Access to XMLHttpRequest from origin 'null' has been blocked by CORS use server to bypass CORS note that Mixed Content loaded over HTTPS will be blocked, the content must be served over HTTPS. adding following code to the HTML page, since we are using the third party API which is not controlled by us. <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

    avoid the specification of the username and password at every git push

    1. Associate the SSH key with the remote repository This step varies, depending on how your remote is set up. If it is a GitHub repository and you have administrative privileges, go to settings and click 'add SSH key'. Copy the contents of your ~/.ssh/id_rsa.pub into the field labeled 'Key'. If your repository is administered by somebody else, give the administrator your id_rsa.pub. If your remote repository is administered by your, you can use this command for example: scp ~/.ssh/id_rsa.pub YOUR_USER@YOUR_IP:~/.ssh/authorized_keys/id_rsa.pub 2. Set your remote URL to a form that supports SSH 1 If you have done the steps above and are still getting the password prompt, make sure your repo URL is in the form git+ssh://git@github.com/username/reponame.git as opposed to https://github.com/username/reponame.git To see your repo URL, run: git remote show origin You can change the URL with: git remote set-url origin git+ssh://git@github.com/username/reponame.git Git - remote: Repository not found Permanently authenticating with Git repositories, Run the following command to enable credential caching. git config credential.helper store git push https://github.com/repo.git For window Delete the credentials from Credential Manager. Open Control Panel from the Start menu. Select User Accounts. Select the "Credential Manager". Click on "Manage Windows Credentials". Delete any credentials related to Git or GitHub. Once you deleted all then try to clone again. I was also facing the same issue remote: Repository not found fatal: repository 'https://github.com/MyRepo/project.git/' not found I uninstalled the git credentials manager and reinstalled it and then I could easily pull and push to the repository. Here are the commands

    What is React?

    React is a JavaScript library created by Facebook React is a User Interface (UI) library React is a tool for building UI components

    Adding React to an HTML Page

    This quickstart tutorial will add React to a page like this:

    Example

    <!DOCTYPE html> <html lang="en"> <title>Test React</title> <!-- Load React API --> <script src= "https://unpkg.com/react@16/umd/react.production.min.js"></script> <!-- Load React DOM--> <script src= "https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script> <!-- Load Babel Compiler --> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> <body> <script type="text/babel"> // JSX Babel code goes here </script> </body> </html>

    What is Babel?

    Babel is a JavaScript compiler that can translate markup or programming languages into JavaScript. With Babel, you can use the newest features of JavaScript (ES6 - ECMAScript 2015). Babel is available for different conversions. React uses Babel to convert JSX into JavaScript. Please note that <script type="text/babel"> is needed for using Babel.

    What is JSX?

    JSX stands for JavaScript XML. JSX is an XML/HTML like extension to JavaScript.

    Example

    const element = <h2>Hello World!</h2> As you can see above, JSX is not JavaScript nor HTML. JSX is a XML syntax extension to JavaScript that also comes with the full power of ES6 (ECMAScript 2015). Just like HTML, JSX tags can have a tag names, attributes, and children. If an attribute is wrapped in curly braces, the value is a JavaScript expression. Note that JSX does not use quotes around the HTML text string.

    React DOM Render

    The method ReactDom.render() is used to render (display) HTML elements:

    Example

    <div id="id01">Hello World!</div> <script type="text/babel">ReactDOM.render( <h2>Hello React!</h2>, document.getElementById('id01')); </script>

    JSX Expressions

    Expressions can be used in JSX by wrapping them in curly {} braces.

    Example

    <div id="id01">Hello World!</div> <script type="text/babel"> const name = 'John Doe'; ReactDOM.render( <h2>Hello {name}!</h2>, document.getElementById('id01')); </script>

    React Elements

    React applications are usually built around a single HTML element. React developers often call this the root node (root element): <div id="root"></div> React elements look like this: const element = <h2>Hello React!</h2> Elements are rendered (displayed) with the ReactDOM.render() method: ReactDOM.render(element, document.getElementById('root')); React elements are immutable. They cannot be changed. The only way to change a React element is to render a new element every time:

    Example

    function tick() { const element = (<h2>{new Date().toLocaleTimeString()}</h2>); ReactDOM.render(element, document.getElementById('root')); } setInterval(tick, 1000);

    React Components

    React components are JavaScript functions. This example creates a React component named "Welcome":

    Example

    function Welcome() { return <h2>Hello React!</h2>; } ReactDOM.render(<Welcome />, document.getElementById('root')); React can also use ES6 classes to create components. This example creates a React component named Welcome with a render method:

    Example

    class Welcome extends React.Component { render() { return(<h2>Hello React!</h2>); } } ReactDOM.render(<Welcome />, document.getElementById('root'));

    React Component Properties

    This example creates a React component named "Welcome" with property arguments:

    Example

    function Welcome(props) { return <h2>Hello {props.name}!</h2>; } ReactDOM.render(<Welcome name="John Doe"/>, document.getElementById('root')); React can also use ES6 classes to create components. This example also creates a React component named "Welcome" with property arguments:

    Example

    class Welcome extends React.Component { render() { return(<h2>Hello {this.props.name}</h2>); } } ReactDOM.render(<Welcome name="John Doe"/>, document.getElementById('root'));

    JSX Compiler

    The examples on this page compiles JSX in the browser. For production code, the compilation should be done separately.

    Create React Application

    Facebook has created a Create React Application with everything you need to build a React app. It is a development server that uses Webpack to compile React, JSX, and ES6, auto-prefix CSS files. The Create React App uses ESLint to test and warn about mistakes in the code. To create a React App run the following code on your terminal:

    Example

    npx create-react-app react-tutorial Make sure you have Node.js 5.2 or higher. Otherwise you must install npx:

    Example

    npm i npx Start one folder up from where you want your application to stay:

    Example

    C:\Users\myUser>npx create-react-app react-tutorial

    Success Result:

    npx: installed 63 in 10.359s Creating a new React app in C:\Users\myUser\react-tutorial. Installing packages. This might take a couple of minutes. Installing react, react-dom, and react-scripts... + react-dom@16.5.2 + react@16.5.2 + react-scripts@2.0.4 added 1732 packages from 664 contributors and audited 31900 packages in 355.501s found 0 vulnerabilities+ react@16.5.2 Success! Created react-tutorial at C:\Users\myUser\react-tutorial Inside that directory, you can run several commands: npm start Starts the development server. npm run build Bundles the app into static files for production. npm test Starts the test runner. npm run eject Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can't go back! We suggest that you begin by typing: cd react-tutorial npm start

    delay refresh by javascript

    $(document).ready(function() { timeDelay = 60*1000 * Number(prompt("alarm delay in minutes: ")) setInterval('window.location.reload()', timeDelay); });

    calculate the centre of a circle given three points

    https://stackoverflow.com/questions/32861804/how-to-calculate-the-centre-point-of-a-circle-given-three-points Translate the three points to bring one of them at the origin (subtract (X0,Y0)). The equation of a circle through two points and the origin can be written 2X.Xc + 2Y.Yc = X² + Y² (refer to: https://www.math-only-math.com/circle-passes-through-the-origin.html) Plugging the coordinates of the two points, you get an easy system of two equations in two unknowns, and by Cramer Xc = (Z1.Y2 - Z2.Y1) / D Yc = (X1.Z2 - X2.Z1) / D D = 2(X1.Y2 - X2.Y1), Z1 = X1²+Y1², Z2 = X2²+Y2² to be translated back (add (X0,Y0)). The formula fails when the three points are aligned, which is diagnosed by D = 0 (or small in comparison to the numerators). X1-= X0; Y1-= Y0; X2-= X0; Y2-= Y0; double Z1= X1 * X1 + Y1 * Y1; double Z2= X2 * X2 + Y2 * Y2; double D= 2 * (X1 * Y2 - X2 * Y1); double Xc= (Z1 * Y2 - Z2 * Y1) / D + X0; double Yc= (X1 * Z2 - X2 * Z1) / D + Y0; function CalculateCircleCenter(A,B,C) { var yDelta_a = B.y - A.y; var xDelta_a = B.x - A.x; var yDelta_b = C.y - B.y; var xDelta_b = C.x - B.x; center = []; var aSlope = yDelta_a / xDelta_a; var bSlope = yDelta_b / xDelta_b; center.x = (aSlope*bSlope*(A.y - C.y) + bSlope*(A.x + B.x) - aSlope*(B.x+C.x) )/(2* (bSlope-aSlope) ); center.y = -1*(center.x - (A.x+B.x)/2)/aSlope + (A.y+B.y)/2; return center; } All you need to do is pass it 3 points : var threePoints = [{x:1, y: 2},{x:4, y: 4},{x:6, y: 2} ] console.log(CalculateCircleCenter(threePoints[0],threePoints[1],threePoints[2]))

    to change the default voice in the browser

    The speech API spec says that browsers can decide which voice to use by default, and that each utterance language may have a different default voice. The default utterence language is decided by the HTML lang attribute: This implies that, to use a British voice by default: <html lang="en-GB"> <script> var utterance = new SpeechSynthesisUtterance('Toodle pip'); window.speechSynthesis.speak(utterance); </script> However, this did not change the default voice for me in Chrome 46 (my default language is en-GB; I also get a German voice by default). You could use navigator.language as the default utterance language, but according to this answer it is not a reliable indicator of browser settings (for me it evaluates to en-US, which is in my list of languages but is not my default). Chrome seems to ignore the HTML lang property. The solution is to set the property of the utterance: <script> var utterance = new SpeechSynthesisUtterance('Toodle pip'); utterance.lang='en-US'; // for US english, en-GR for british window.speechSynthesis.speak(utterance); </script> SpeechSynthesis.getVoices() will return several options for English (United States, Australia, Nigeria, India, and United Kingdom) but only one is available at a time. You can pick which one by going to the Settings app, then Controls->Language and input->Text-to-speech options.

    The lang property of the SpeechSynthesisUtterance interface

    gets and sets the language of the utterance. If unset, the app's (i.e. the lang value) lang will be used, or the user-agent default if that is unset too. Syntax var myLang = speechSynthesisUtteranceInstance.lang; speechSynthesisUtteranceInstance.lang = 'en-US'; Examples var synth = window.speechSynthesis; var inputForm = document.querySelector('form'); var inputTxt = document.querySelector('input'); var voiceSelect = document.querySelector('select'); var voices = synth.getVoices(); ... inputForm.onsubmit = function(event) { event.preventDefault(); var utterThis = new SpeechSynthesisUtterance(inputTxt.value); var selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name'); for(i = 0; i < voices.length ; i++) { if(voices[i].name === selectedOption) { utterThis.voice = voices[i]; } } utterThis.lang = 'en-US'; synth.speak(utterThis); inputTxt.blur(); } SpeechSynthesisUtterance() Properties lang pitch rate text voice volume Events boundary end error mark pause resume start Inheritance: EventTarget

    radio button



    Create a radio button

    Following is a simple code for creating a group of radio buttons. <p> Choose your favroite season: </p> <input type="radio" name="JTP" id="summer" value="summer">Summer<br> <input type="radio" name="JTP" id="winter" value="winter">Winter<br> <input type="radio" name="JTP" id="rainy" value="rainy">Rainy<br> <input type="radio" name="JTP" id="autumn" value="autumn">Autumn<br>

    Check a radio button

    We do not need to write any specific code to check the radio button. They can be checked once they are created or specified in HTML form. However, we have to write the JavaScript code to get the value of the checked radio button, which we will see in the chapter below:

    Check the radio button is selected or not

    There are two ways in JavaScript to check the marked radio button or to identify which radio button is selected. JavaScript offers two DOM methods for this.
  • getElementById
  • querySelector
  • The input radio checked property is used to check whether the checkbox is selected or not. Use document.getElementById('id').checked method for this. It will return the checked status of the radio button as a Boolean value. It can be either true or false. True - If radio button is selected. False - If radio button is not selected/ checked. See the JavaScript code below to know how it works:

    Example

    For example, we have a radio button named Summer and id = 'summer'. Now, we will check using this button id that the radio button is marked or not. if(document.getElementById('summer').checked == true) { document.write("Summer radio button is selected"); } else { document.write("Summer radio button is not selected"); }

    querySelector()

    The querySelector() function is a DOM method of JavaScript. It uses the common name property of radio buttons inside it. This method is used as given below to check which radio button is selected. document.querySelector('input[name="JTP"]:checked')

    Example

    For example, we have a group of radio buttons having the name property name = 'season' for all buttons. Now, between these buttons named season we will check which one is selected. var getSelectedValue = document.querySelector( 'input[name="season"]:checked'); if(getSelectedValue != null) { document.write("Radio button is selected"); } else { document.write("Nothing has been selected"); }

    Get the value of checked radio button:

    Using getElementById ()

    Following is the code to get the value of checked radio button using getElementById() method: if(document.getElementById('summer').checked) { var selectedValue = document.getElementById('summer').value; alert("Selected Radio Button is: " + selectedValue); }

    Using querySelector()

    Following is the code to get the value of checked radio button using querySelector() method: var getSelectedValue = document.querySelector( 'input[name="season"]:checked'); if(getSelectedValue != null) { alert("Selected radio button values is: " + getSelectedValue.value); }

    show all available languages

    speechSynthesis.getVoices().forEach(voice => { console.log(voice.name, voice.lang) }) Microsoft David Desktop - English (United States) en-US txt2speech.html:59 Microsoft Hazel Desktop - English (Great Britain) en-GB txt2speech.html:59 Microsoft Zira Desktop - English (United States) en-US txt2speech.html:59 Microsoft Huihui Desktop - Chinese (Simplified) zh-CN txt2speech.html:59 Microsoft Tracy Desktop - Chinese(Traditional, HongKong SAR) zh-HK txt2speech.html:59 Microsoft Hanhan Desktop - Chinese (Taiwan) zh-TW txt2speech.html:59 Google Deutsch de-DE txt2speech.html:59 Google US English en-US txt2speech.html:59 Google UK English Female en-GB txt2speech.html:59 Google UK English Male en-GB txt2speech.html:59 Google español es-ES txt2speech.html:59 Google español de Estados Unidos es-US txt2speech.html:59 Google français fr-FR txt2speech.html:59 Google हिन्दी hi-IN txt2speech.html:59 Google Bahasa Indonesia id-ID txt2speech.html:59 Google italiano it-IT txt2speech.html:59 Google 日本語 ja-JP txt2speech.html:59 Google 한국의 ko-KR txt2speech.html:59 Google Nederlands nl-NL txt2speech.html:59 Google polski pl-PL txt2speech.html:59 Google português do Brasil pt-BR txt2speech.html:59 Google русский ru-RU txt2speech.html:59 Google 普通话(中国大陆) zh-CN txt2speech.html:59 Google 粤語(香港) zh-HK txt2speech.html:59 Google 國語(臺灣) zh-TW

    Set selected radio from radio group with a value

    var value = 5; $("input[name=mygroup][value=" + value + "]").attr('checked', 'checked'); $("input[name=mygroup]").val([5]); $('input:radio[name="mygroup"][value="5"]').attr('checked',true); Since jQuery 1.6, you can also use the .prop method with a boolean value (this should be the preferred method): $("input[name=mygroup][value=" + value + "]").prop('checked', true); Code To Remove Checked Attribute from all radio buttons of one radio button group - $('[name="radioSelectionName"]').removeAttr('checked');

    Tesseract.js Examples

    Tesseract.js Examples basic const { createWorker } = require('tesseract.js'); const worker = createWorker(); (async () => { await worker.load(); await worker.loadLanguage('eng'); await worker.initialize('eng'); const { data: { text } } = await worker.recognize('https://tesseract.projectnaptha.com/img/eng_bw.png'); console.log(text); await worker.terminate(); })(); with multiple languages, separate by '+' const { createWorker } = require('tesseract.js'); const worker = createWorker(); (async () => { await worker.load(); await worker.loadLanguage('eng+chi_tra'); await worker.initialize('eng+chi_tra'); const { data: { text } } = await worker.recognize('https://tesseract.projectnaptha.com/img/eng_bw.png'); console.log(text); await worker.terminate(); })();

    Express Middleware through Examples

    https://developer.okta.com/blog/2018/09/13/build-and-understand-express-middleware-through-examples

    If you’ve done any significant Node development in the past seven or eight years, you’ve probably used Express to build a web server at some point. While you can create a server in Node without using a library, it doesn’t give you a lot out of the box and can be quite cumbersome to add functionality. Express is a minimalist, “unopinionated” server library and has become the de facto standard for building web apps in Node. To understand Express, you need to understand Express Middleware.

    What is Express Middleware?

    Middleware literally means anything you put in the middle of one layer of the software and another. Express middleware are functions that execute during the lifecycle of a request to the Express server. Each middleware has access to the HTTP request and response for each route (or path) it’s attached to. In fact, Express itself is compromised wholly of middleware functions. Additionally, middleware can either terminate the HTTP request or pass it on to another middleware function using next (more on that soon). This “chaining” of middleware allows you to compartmentalize your code and create reusable middleware. In this article I’ll explain what middleware is, why you would use it, how to use existing Express middleware, and how to write your own middleware for Express.

    Requirements to Write Express Middleware

    There are a few things you will need installed to create, use, and test Express middleware. First, you will need Node and NPM. To ensure you have them installed, you can run: npm -v && node -v You should see the Node and NPM versions you have installed. If you get an error, you need to install Node. I’m using the latest version of both as of the time of this article, which is Node 10.9.0 and NPM 6.4.1, but all the examples should work with Node versions 8+ and NPM versions 5+. I will also be using Express version 4.x. This is important because major changes were made from version 3.x to 4.x. It will also be helpful to have Postman installed to test routes using any HTTP verbs other than GET.

    Express Middleware: The Basics

    To get started, you’ll use the most basic of Express’ built-in middleware. This will give you the chance to see how middleware is used, and how Express middleware is structured. Create a new project and npm init it… npm init npm install express --save Create server.js and paste the following code: const express = require('express'); const app = express(); app.get('/', (req, res, next) => { res.send('Welcome Home'); }); app.listen(3000); Run the server via node server.js, access http://localhost:3000, and you should see “Welcome Home” printed in your browser. The app.get() function is Application-level Middleware. You’ll notice the parameters passed to the method are req, res, and next. These are the incoming request, the response being written, and a method to call to pass the call to the next middleware function once the current middleware is finished. In this case, once the response is sent, the function exits. You could also chain other middleware here by calling the next() method. Let’s take a look at a few more examples of the different types of middleware.

    Express Request Logging Middleware Example

    In Express, you can set up middleware to be “global” middleware; meaning it will be called for every incoming request. Change the contents of server.js to: const express = require('express'); const app = express(); app.use((req, res, next) => { console.log(req); next(); }); app.get('/', (req, res, next) => { res.send('Welcome Home'); }); app.listen(3000); This time, when you go to http://localhost:3000 you should see the same thing in your browser window, but back in the console window you will see the output of the incoming request object. The middleware logs out the request object and then calls next(). The next middleware in the pipeline handles the get request to the root URL and sends back the text response. Using app.use() means that this middleware will be called for every call to the application.

    Restrict Express Request Content Type Example

    In addition to running middleware for all calls, you could also specify to only run middleware for specific calls. Change the server.js file again to: const express = require('express'); const app = express(); const requireJsonContent = () => { return (req, res, next) => { if (req.headers['content-type'] !== 'application/json') { res.status(400).send('Server requires application/json') } else { next() } } } app.get('/', (req, res, next) => { res.send('Welcome Home'); }); app.post('/', requireJsonContent(), (req, res, next) => { res.send('You sent JSON'); }) app.listen(3000); This time, start the server by running: node server.js To test this, open up Postman and create a post request to http://localhost:3000. Don’t set any headers and run the request. You will get back the “Server requires application/json” message. Now go back and add the Content-Type header with a value of application/json and run the request again. You will get the “You sent JSON” message back from the server. This app.post() method call adds the requireJsonContent() middleware function to ensure the incoming request payload has a Content-Type header value set to application/json. If it doesn’t pass the check, an error response is sent. If it does, the request is then handed off to the next piece of middleware in the chain via the next() method.

    Third-Party Express Middleware

    You’ve built a couple of custom middlewares to far, but there are lots of packages already built to do the things you might normally want to do. In fact, you’ve used the simple routing middleware library by using the app.get() or app.post() middleware functions. There are thousands of middleware libraries for doing things like parsing incoming data, routing, and authorization. Okta has an Express middleware for OIDC security that I’ll show you to demonstrate using third-party middleware libraries.

    Why Okta for Express Applications

    At Okta, our goal is to make identity management a lot easier, more secure, and more scalable than what you’re used to. Okta is a cloud service that allows developers to create, edit, and securely store user accounts and user account data, and connect them with one or multiple applications. Our API enables you to: Authenticate and authorize your users Store data about your users Perform password-based and social login Secure your application with multi-factor authentication And much more! Check out our product documentation

    Okta’s OIDC Express Middleware

    To install Okta’s OIDC middleware for Express, run: npm install @okta/oidc-middleware@0.1.3 --save Then in the server.js file, you create an instance if the middleware with some configuration options so that Okta knows how to connect to your Okta application. const oidc = new ExpressOIDC({ issuer: 'https://{yourOktaDomain}/oauth2/default', client_id: '{yourClientId}', client_secret: '{yourClientSecret}', redirect_uri: 'http://localhost:3000/authorization-code/callback', scope: 'openid profile' }); You’ll also need to tell Express to use the OIDC middleware router instead of the default router. app.use(oidc.router); Then you use it like any other middleware: app.get('/protected', oidc.ensureAuthenticated(), (req, res) => { res.send('Top Secret'); }); The oidc.ensureAuthenticated() function is a middleware in the Okta library. It runs a function to see if the current user is logged in. If they are, it calls next() to let the app.get() function continue handling the request. If they aren’t it will send back an HTTP 401 (Unauthorized) response.

    Middleware Order is Important

    When a request is received by Express, each middleware that matches the request is run in the order it is initialized until there is a terminating action (like a response being sent). So if an error occurs, all middleware that is meant to handle errors will be called in order until one of them does not call the next() function call.

    Error Handling in Express Middleware

    Express has a built-in default error handler that is inserted at the end of the middleware pipeline that handles any unhandled errors that may have occurred in the pipeline. Its signature adds an error parameter to the standard parameters of request, response, and next. The basic signature looks like this: app.use((err, req, res, next) => { // middleware functionality here }) In order to call an error-handling middleware, you simply pass the error to next(), like this: app.get('/my-other-thing', (req, res, next) => { next(new Error('I am passing you an error!')); }); app.use((err, req, res, next) => { console.log(err); if(!res.headersSent){ res.status(500).send(err.message); } }); In this case, the error handling middleware at the end of the pipeline will handle the error. You might also notice that I checked the res.headersSent property. This just checks to see if the response has already sent the headers to the client. If it hasn’t it sends a 500 HTTP status and the error message to the client. You can also chain error-handling middleware. This is common to handle different types of errors in different ways. For instance: app.get('/nonexistant', (req, res, next) => { let err = new Error('I couldn\'t find it.'); err.httpStatusCode = 404; next(err); }); app.get('/problematic', (req, res, next) => { let err = new Error('I\'m sorry, you can\'t do that, Dave.'); err.httpStatusCode = 304; next(err); }); // handles not found errors app.use((err, req, res, next) => { if (err.httpStatusCode === 404) { res.status(400).render('NotFound'); } next(err); }); // handles unauthorized errors app.use((err, req, res, next) => { if(err.httpStatusCode === 304){ res.status(304).render('Unauthorized'); } next(err); }) // catch all app.use((err, req, res, next) => { console.log(err); if (!res.headersSent) { res.status(err.httpStatusCode || 500).render('UnknownError'); } }); In this case, the middleware checks to see if a 404 (not found) error was thrown. If so, it renders the ‘NotFound’ template page and then passes the error to the next item in the middleware. The next middleware checks to see if a 304 (unauthorized) error was thrown. If it was, it renders the ‘Unauthorized’ page, and passes the error to the next middleware in the pipeline. Finally the “catch all” error handler just logs the error and if no response has been sent, it sends the error’s httpStatusCode (or an HTTP 500 status if none is provided) and renders the ‘UnknownError’ template.

    Learn More About Express Middleware

    For detailed instructions on setting up the Okta OIDC middleware, you can follow the ExpressJS Quickstart. There is also a list of officially supported Express middleware in this GitHub repo you can try out and dig into to learn more Finally, if you’re interested in learning more about how to use Okta, there’s an Okta Node SDK for implementing more user management functionality in your application.

    How To Use And Write Express Middleware



    Middleware is an often misunderstood Middlewaretopic since it sounds and appears very complicated, but in reality middleware is actually really straightforward. The entire idea of middleware is to execute some code before the controller action that sends the response and after the server gets the request from the client. Essentially it is code that executes in the middle of your request, hence the name middleware. Before I get too in depth on the details of middleware, though, I want to setup a basic Express server with two routes.If you prefer to learn visually, check out the video version of this article.

    Setting Up An Express Server

    To get started working with a Node.js project you will need to run npm init -y. This will create a basic package.json file with all of the default values filled in for you. From there the next thing to do is install Express by running npm i express. Lastly, we need to create a server.js file with the following code. const express = require('express') const app = express() app.get('/', (req, res) => { res.send('Home Page') }) app.get('/users', (req, res) => { res.send('Users Page') }) app.listen(3000, () => console.log('Server Started')) This server.js file simply sets up a server on port 3000 that has two routes, a home page route and a users page route. The last thing to do is run node server.js to start up the application and if everything worked you should see a message in the console saying Server Started. You can then open up any browser to localhost:3000 and you should see the message Home Page. If you go to localhost:3000/users you should then see the message Users Page.That is all the basic setup we will need for the rest of this article. As we make changes you will need to restart your server in the console to see the changes take effect.

    What Is Middleware?

    I talked briefly about middleware as functions that execute after the server receives the request and before the controller action sends the response, but there are a few more things that are specific to middleware. The biggest thing is that middleware functions have access to the response (res) and request (req) variables and can modify them or use them as needed. Middleware functions also have a third parameter which is a next function. This function is important since it must be called from a middleware for the next middleware to be executed. If this function is not called then none of the other middleware including the controller action will be called.This is all a bit difficult to understand just from text so in the next section we are going to create a logging middleware that will log the url of the request a user makes.

    How To Create Logging Middleware

    As I mentioned in the previous section, middleware takes three parameters, req, res, and next, so in order to create middleware we need to create a function that has those three inputs.const express = require('express') const app = express() app.get('/', (req, res) => { res.send('Home Page') }) app.get('/users', (req, res) => { res.send('Users Page') }) function loggingMiddleware(req, res, next) { console.log('Inside Middleware') } app.listen(3000, () => console.log('Server Started')) We now have the shell of a basic middleware function defined with some placeholder content, but the application is not using it. Express has a few different ways you can define middleware to be used, but for this example we will make this middleware execute before every single controller action by adding it to the application level. This can be done by using the use function on the app variable like this.const express = require('express') const app = express() app.use(loggingMiddleware) app.get('/', (req, res) => { res.send('Home Page') }) app.get('/users', (req, res) => { res.send('Users Page') }) function loggingMiddleware(req, res, next) { console.log('Inside Middleware') } app.listen(3000, () => console.log('Server Started')) The application is now using the middleware that we defined and if we restart our server and navigate to any of the pages in our app you will notice that in the console the message Inside Middleware appears. This is great, but there is a slight problem. The application now loads forever and never actually finishes the request. This is because in our middleware we are not calling the next function so the controller action never gets called. We can fix this by calling next after our logging.const express = require('express') const app = express() app.use(loggingMiddleware) app.get('/', (req, res) => { res.send('Home Page') }) app.get('/users', (req, res) => { res.send('Users Page') }) function loggingMiddleware(req, res, next) { console.log('Inside Middleware') next() } app.listen(3000, () => console.log('Server Started')) Now if you restart the server you will notice that everything is logging correctly, and the web page is properly loading. The next thing to do is to actually log out the URL that the user is accessing inside the middleware. This is where the req variable will come in handy.const express = require('express') const app = express() app.use(loggingMiddleware) app.get('/', (req, res) => { res.send('Home Page') }) app.get('/users', (req, res) => { res.send('Users Page') }) function loggingMiddleware(req, res, next) { console.log(`${new Date().toISOString()}: ${req.originalUrl}`) next() } app.listen(3000, () => console.log('Server Started')) The logging middleware is now working 100% correctly on all the routes in the application, but we have only scratched the surface on the usefulness of middleware. In the next example we are going to take a look at creating a simple authorization middleware for the users page.

    Advanced Middleware Example

    To get started we need to create another function to use as middleware.const express = require('express') const app = express() app.use(loggingMiddleware) app.get('/', (req, res) => { res.send('Home Page') }) app.get('/users', (req, res) => { res.send('Users Page') }) function loggingMiddleware(req, res, next) { console.log(`${new Date().toISOString()}: ${req.originalUrl}`) next() } function authorizeUsersAccess(req, res, next) { console.log('authorizeUsersAccess Middleware') next() } app.listen(3000, () => console.log('Server Started')) This is just a shell of a function to be used as middleware, but we can add it to our users page route now in order to ensure that our middleware is only being executed on the users page route. This can be done by adding the function as a parameter to the app.get function for the users page.const express = require('express') const app = express() app.use(loggingMiddleware) app.get('/', (req, res) => { res.send('Home Page') }) app.get('/users', authorizeUsersAccess, (req, res) => { res.send('Users Page') }) function loggingMiddleware(req, res, next) { console.log(`${new Date().toISOString()}: ${req.originalUrl}`) next() } function authorizeUsersAccess(req, res, next) { console.log('authorizeUsersAccess Middleware') next() } app.listen(3000, () => console.log('Server Started')) Now if you restart the server and go to the users page you should see the message authorizeUsersAccess Middleware, but if you go to the home page this message will not show up. We now have middleware that only executes on a single route in the application. The next thing to do is fill in the logic of this function so that if the user does not have access to the page they will get an error message instead.const express = require('express') const app = express() app.use(loggingMiddleware) app.get('/', (req, res) => { res.send('Home Page') }) app.get('/users', authorizeUsersAccess, (req, res) => { res.send('Users Page') }) function loggingMiddleware(req, res, next) { console.log(`${new Date().toISOString()}: ${req.originalUrl}`) next() } function authorizeUsersAccess(req, res, next) { if (req.query.admin === 'true') { next() } else { res.send('ERROR: You must be an admin') } } app.listen(3000, () => console.log('Server Started')) This middleware now checks to see if the query parameter admin=true is in the URL and if it is not an error message is shown to the user. You can test this by going to http://localhost:3000/users and you will see an error message explaining that you are not a admin. If you instead go to http://localhost:3000/users?admin=true you will be sent the normal users page since you set the query parameter of admin to true.One other thing that is really useful with middleware is the ability to send data between middleware. There is no way to do this with the next function, but you can modify the req or res variables to set your own custom data. For example in the previous example if we wanted to set a variable to true if the user was a admin we could easily do that.const express = require('express') const app = express() app.use(loggingMiddleware) app.get('/', (req, res) => { res.send('Home Page') }) app.get('/users', authorizeUsersAccess, (req, res) => { console.log(req.admin) res.send('Users Page') }) function loggingMiddleware(req, res, next) { console.log(`${new Date().toISOString()}: ${req.originalUrl}`) next() } function authorizeUsersAccess(req, res, next) { if (req.query.admin === 'true') { req.admin = true next() } else { res.send('ERROR: You must be an admin') } } app.listen(3000, () => console.log('Server Started')) This code sets an admin variable on the req object which is then accessed in the controller action for the users page.

    Middleware Additional Information

    This is the majority of everything you need to know about middleware functions, but there a few extra things that are important to know.

    1. Controller Actions Are Just Like Middleware

    One thing you may have noticed is that controller actions which have a req, and res variable are very similar to middleware. That is because they are essentially middleware, but with no other middleware that comes after them. They are the end of the chain which is why there are never any next calls inside the controller action.

    2. Calling next Is Not The Same As Calling return

    By far the biggest mistake I see developers make when working with middleware is that they treat the next function as if it exited out of the middleware. Take for example this middleware.function middleware(req, res, next) { if (req.valid) { next() } res.send('Invalid Request') } At face value this code looks correct. If the request is valid then the next function is called and if it isn't valid then it is sending an error message. The problem is that the next function does not actually return from the middleware function. This means that when next is called the next middleware will execute and that will continue until no more middleware is left to execute. Then after all the middleware after this middleware is done executing the code will pick back up right after the next call in each of the middleware. That means that in this middleware the error message will always be sent to the user which is obviously not what you want. An easy way to prevent this is by simply returning when you call nextfunction middleware(req, res, next) { if (req.valid) { return next() } res.send('Invalid Request') } Now the code will no longer execute after calling next since it will return out of the function. An easy way to see this issue in action is with the following code.const express = require('express') const app = express() app.get('/', middleware, (req, res) => { console.log('Inside Home Page') res.send('Home Page') }) function middleware(req, res, next) { console.log('Before Next') next() console.log('After Next') } app.listen(3000, () => console.log('Server Started')) When you run this code and go to the home page the console will print out the following messages in order.Before Next Inside Home Page After NextEssentially what is happening is the middleware is called and it logs out the before statement. Then next is called so the next set of middleware is called which is the controller action where the home page message is logged. Lastly the controller action finishes executing so the middleware then executes the code after next which logs out the after statement.

    3. Middleware Will Execute In Order

    This may seem self-explanatory but when you define middleware it will execute in the order it is used. Take for example the following code.const express = require('express') const app = express() app.use(middlewareThree) app.use(middlewareOne) app.get('/', middlewareTwo, middlewareFour, (req, res) => { console.log('Inside Home Page') res.send('Home Page') }) function middlewareOne(req, res, next) { console.log('Middleware One') next() } function middlewareTwo(req, res, next) { console.log('Middleware Two') next() } function middlewareThree(req, res, next) { console.log('Middleware Three') next() } function middlewareFour(req, res, next) { console.log('Middleware Four') next() } app.listen(3000, () => console.log('Server Started')) Since the app.use statements come first the middleware in those statements will be executed first in the order they were added. Next the app.get middleware is defined and again they will be executed in the order they are in the app.get function. This will lead to the following console output if ran.Middleware Three Middleware One Middleware Two Middleware Four

    Conclusion

    That is all there is to know about middleware. Middleware is incredibly powerful for cleaning up code and making things like user authorization and authentication much easier, but it can be used for so much more than just that because of the incredible flexibility of middleware.

    Tesseract.js: OCR Remote Images

    Tesseract.js works with a <script> tag via local copy or CDN, with webpack via npm and on Node.js with npm/yarn. CDN <!-- v2 --> <script src='https://unpkg.com/tesseract.js@v2.1.0/dist/tesseract.min.js'></script> After including the script the Tesseract variable will be globally available.

    Tesseract.js is a JavaScript OCR library based on the world’s most popular Optical Character Recognition engine. It’s insanely easy to use on both the client-side and on the server with Node.js. Server side, Tesseract.js only works with local images. But, with a little help from the request Node package, we can download a remote image from a URL and then OCR it with Tesseract.js. We’ll tackle this in three steps: Write code to download a remote file with Node Write code to OCR that local file with Tessearct Put the two snippets together The final product will take just fifteen lines of JavaScript to OCR images from a URL. Sound good? Let’s get started.

    Download a remote file with Node.js

    Request “is designed to be the simplest way possible to make http calls” in Node.js. We’ll use it to open a URL and then pipe the stream to the local file system using the Node.js standard library. When finished, we’ll fire off a callback. Paste this code into a new file called download.js: var request = require('request') var fs = require('fs') var url = 'http://tesseract.projectnaptha.com/img/eng_bw.png' var filename = 'pic.png' var writeFileStream = fs.createWriteStream(filename) request(url).pipe(writeFileStream).on('close', function() { console.log(url, 'saved to', filename) }) We’re using the sample image from the Tesseract documentation, which looks like this: Install request and run the script: npm install request node download.js Check your directory and you should see a new file. Now let’s OCR that downloaded file.

    OCR a local image with Tesseract.js and Node.js

    Getting started with Tesseract.js is dead simple. Paste this code into a file called ocr.js. var Tesseract = require('tesseract.js') var filename = 'pic.png' Tesseract.recognize(filename) .progress(function(p) { console.log('progress', p) }) .catch(err => console.error(err)) .then(function(result) { console.log(result.text) process.exit(0) }) Install Tesseract.js and run the script: npm install tesseract.js node ocr.js Once Tesseract starts up (~10 seconds on my MacBook Pro), we’ll see progress updates and then find the recognized text in result.text. There’s a ton more data hiding in result if you’re inclined to go digging. We now have code to download a remote file and code to OCR a local file — we just need to put them together.

    OCR a remote image with Tesseract.js

    Paste this code into a new file called download-and-ocr.js: var Tesseract = require('tesseract.js') var request = require('request') var fs = require('fs') var url = 'http://tesseract.projectnaptha.com/img/eng_bw.png' var filename = 'pic.png' var writeFile = fs.createWriteStream(filename) request(url).pipe(writeFile).on('close', function() { console.log(url, 'saved to', filename) Tesseract.recognize(filename) .progress(function(p) { console.log('progress', p) }) .catch(err => console.error(err)) .then(function(result) { console.log(result.text) process.exit(0) }) }); All we’ve done here is: Start with the script from download.js Require Tesseract.js Paste the the code from ocr.js into the callback that’s run when the file finishes downloading. Give the script a run, swapping in your own picture URL if you so please: node download-and-ocr.js Next Steps That’s it! Three simple steps and we’re using Tesseract.js to perform OCR on an image from a URL. My personal motivation is to use Tesseract.js in conjunction with Twilio MMS to process photos that I snap while running around NYC. Perhaps I’ll grep phone numbers out of ads and run them through our Lookup API to see if they’re Twilio numbers. What are you going to build? If you’d like to learn more, check out: Docs for Request file streaming in Node.js Full API docs for Tesseract.js Twilio JavaScript quickstarts If you enjoyed this post, give a shout-out to Guillermo Webster and Kevin Kwok for their heroic effort porting Tesseract to JS. And, of course, feel free to drop me a line if you have any questions or build something you’d like to show off.

    console methods



    methods

     console.assert() Log a message and stack trace to console if the first argument is false.  console.clear() Clear the console.  console.count() Log the number of times this line has been called with the given label.  console.countReset() Resets the value of the counter with the given label.  console.debug() Outputs a message to the console with the log level debug.  console.dir() Displays an interactive listing of the properties of a specified JavaScript object. This listing lets you use disclosure triangles to examine the contents of child objects.  console.dirxml() Displays an XML/HTML Element representation of the specified object if possible or the JavaScript Object view if it is not possible.  console.error() Outputs an error message. You may use string substitution and additional arguments with this method.  console.exception() An alias for error().  console.group() Creates a new inline group, indenting all following output by another level. To move back out a level, call groupEnd().  console.groupCollapsed() Creates a new inline group, indenting all following output by another level. However, unlike group() this starts with the inline group collapsed requiring the use of a disclosure button to expand it. To move back out a level, call groupEnd().  console.groupEnd() Exits the current inline group.  console.info() Informative logging of information. You may use string substitution and additional arguments with this method.  console.log() For general output of logging information. You may use string substitution and additional arguments with this method. console.profile() Starts the browser's built-in profiler (for example, the Firefox performance tool). You can specify an optional name for the profile. console.profileEnd() Stops the profiler. You can see the resulting profile in the browser's performance tool (for example, the Firefox performance tool).  console.table() Displays tabular data as a table.  console.time() Starts a timer with a name specified as an input parameter. Up to 10,000 simultaneous timers can run on a given page.  console.timeEnd() Stops the specified timer and logs the elapsed time in milliseconds since it started.  console.timeLog() Logs the value of the specified timer to the console. console.timeStamp() Adds a marker to the browser's Timeline or Waterfall tool.  console.trace() Outputs a stack trace.  console.warn() Outputs a warning message. You may use string substitution and additional arguments with this method.

    Examples

     Outputting text to the console

    The most frequently-used feature of the console is logging of text and other data. There are four categories of output you can generate, using the console.log(), console.info(), console.warn(), and console.error() methods respectively. Each of these results in output styled differently in the log, and you can use the filtering controls provided by your browser to only view the kinds of output that interest you. There are two ways to use each of the output methods; you can pass in a list of objects whose string representations get concatenated into one string, then output to the console, or you can pass in a string containing zero or more substitution strings followed by a list of objects to replace them.

    Outputting a single object

    The simplest way to use the logging methods is to output a single object: var someObject = { str: "Some text", id: 5 }; console.log(someObject); The output looks something like this: [09:27:13.475] ({str:"Some text", id:5})

    Outputting multiple objects

    You can also output multiple objects by listing them when calling the logging method, like this: var car = "Dodge Charger"; var someObject = { str: "Some text", id: 5 }; console.info("My first car was a", car, ". The object is:", someObject); This output will look like this: [09:28:22.711] My first car was a Dodge Charger . The object is: ({str:"Some text", id:5})

    Using string substitutions

    When passing a string to one of the console object's methods that accepts a string (such as log()), you may use these substitution strings: %o or %O Outputs a JavaScript object. Clicking the object name opens more information about it in the inspector. %d or %i Outputs an integer. Number formatting is supported, for example console.log("Foo %.2d", 1.1) will output the number as two significant figures with a leading 0: Foo 01 %s Outputs a string. %f Outputs a floating-point value. Formatting is supported, for example console.log("Foo %.2f", 1.1) will output the number to 2 decimal places: Foo 1.10 Note: Precision formatting doesn't work in Chrome Each of these pulls the next argument after the format string off the parameter list. For example: for (var i=0; i<5; i++) { console.log("Hello, %s. You've called me %d times.", "Bob", i+1); } The output looks like this: [13:14:13.481] Hello, Bob. You've called me 1 times. [13:14:13.483] Hello, Bob. You've called me 2 times. [13:14:13.485] Hello, Bob. You've called me 3 times. [13:14:13.487] Hello, Bob. You've called me 4 times. [13:14:13.488] Hello, Bob. You've called me 5 times.

    Styling console output

    You can use the %c directive to apply a CSS style to console output: console.log("This is %cMy stylish message", "color: yellow; font-style: italic; background-color: blue;padding: 2px"); The text before the directive will not be affected, but the text after the directive will be styled using the CSS declarations in the parameter. You may use %c multiple times: console.log("Multiple styles: %cred %corange", "color: red", "color: orange", "Additional unformatted message"); The properties usable along with the %c syntax are as follows (at least, in Firefox — they may differ in other browsers): background and its longhand equivalents. border and its longhand equivalents border-radius box-decoration-break box-shadow clear and float color cursor display font and its longhand equivalents line-height margin outline and its longhand equivalents padding text-* properties such as text-transform white-space word-spacing and word-break writing-mode Note: The console message behaves like an inline element by default. To see the effects of padding, margin, etc. you should set it to for example display: inline-block.

     Using groups in the console

    You can use nested groups to help organize your output by visually combining related material. To create a new nested block, call console.group(). The console.groupCollapsed() method is similar but creates the new block collapsed, requiring the use of a disclosure button to open it for reading. To exit the current group, call console.groupEnd(). For example, given this code: console.log("This is the outer level"); console.group("First group"); console.log("In the first group"); console.group("Second group"); console.log("In the second group"); console.warn("Still in the second group"); console.groupEnd(); console.log("Back to the first group"); console.groupEnd(); console.debug("Back to the outer level"); The output looks like this: Demo of nested groups in Firefox console

     Timers

    You can start a timer to calculate the duration of a specific operation. To start one, call the console.time() method, giving it a name as the only parameter. To stop the timer, and to get the elapsed time in milliseconds, just call the console.timeEnd() method, again passing the timer's name as the parameter. Up to 10,000 timers can run simultaneously on a given page. For example, given this code: console.time("answer time"); alert("Click to continue"); console.timeLog("answer time"); alert("Do a bunch of other stuff..."); console.timeEnd("answer time"); Will log the time needed by the user to dismiss the alert box, log the time to the console, wait for the user to dismiss the second alert, and then log the ending time to the console: Notice that the timer's name is displayed both when the timer is started and when it's stopped. Note: It's important to note that if you're using this to log the timing for network traffic, the timer will report the total time for the transaction, while the time listed in the network panel is just the amount of time required for the header. If you have response body logging enabled, the time listed for the response header and body combined should match what you see in the console output.

     Stack traces

    The console object also supports outputting a stack trace; this will show you the call path taken to reach the point at which you call console.trace(). Given code like this: function foo() { function bar() { console.trace(); } bar(); } foo(); The output in the console looks something like this:

    to hide url from browser using Javascript

    <a href="#" onclick="location.href='https://actualwizard.com'">Mousing over this URL will display the current URL followed by a pound symbol.</a>

    Create a circle out of three points

    https://github.com/infusion/Circle.js Circle.js https://www.xarg.org/2018/02/create-a-circle-out-of-three-points/" Create a circle out of three points var circle = require('circle.js'); <script src="circle.js"></script> <script> var p1 = {x: 20, y: 10}; var p2 = {x: 10, y: 100}; var p3 = {x: 0, y: 50}; function circleFromThreePoints(p1, p2, p3) { var x1 = p1.x; var y1 = p1.y; var x2 = p2.x; var y2 = p2.y; var x3 = p3.x; var y3 = p3.y; var a = x1 * (y2 - y3) - y1 * (x2 - x3) + x2 * y3 - x3 * y2; var b = (x1 * x1 + y1 * y1) * (y3 - y2) + (x2 * x2 + y2 * y2) * (y1 - y3) + (x3 * x3 + y3 * y3) * (y2 - y1); var c = (x1 * x1 + y1 * y1) * (x2 - x3) + (x2 * x2 + y2 * y2) * (x3 - x1) + (x3 * x3 + y3 * y3) * (x1 - x2); var x = -b / (2 * a); var y = -c / (2 * a); return { x: x, y: y, r: Math.hypot(x - x1, y - y1) }; } </script> Functions intersect(a, b) Determines if two circles intersect intersection(a, b) Calculates the intersection points of two circles intersectionArea(a, b) Calculates the intersection area of two circles area(a) Calculates the area of a circle height(a) Calculates the height of a circle. Obviously, this is the same as the width. width(a) Calculates the width of a circle. Obviously, this is the same as the height. perimater(a) Calculates the perimeter of a circle center(a) Calculates the center point of a circle. Simply it's coordinates. insetBy(a) Resizes the circle by a given value on the center fromThreePoints(p1, p2, p3) Caclulates a circle {x, y, r} with given three {x, y} points

    auto scroll

    function pageScroll() { window.scrollBy(0,1); scrolldelay = setTimeout(pageScroll,10); } pageScroll(); stop-scrolling Do it simply by adding a class to the body: .stop-scrolling { height: 100%; overflow: hidden; } Add the class then remove when you want to re-enable scrolling modify: chkKey() { if(testkey == " "){ randomScroll();} add: function randomScroll(){ // $('body').addClass('stop-scrolling') // $("body").removeClass('stop-scrolling'); // $("body").toggleClass('stop-scrolling'); topicpointer = Math.floor(Math.random() * topicLength) window.location = "#topic-" + topicpointer; pageScroll(); } function pageScroll() { window.scrollBy(0,1); scrolldelay = setTimeout(pageScroll,10); } call: randomScroll()

    Disable Scrolling on Body

    https://linuxhint.com/disable-scrolling-javascript/ Set height and overflow: html, body {margin: 0; height: 100%; overflow: hidden} HTML css works fine <body scroll="no">

    Records and Tuples

    Records and Tuples are an upcoming feature for Javascript, which may be familiar if you have used other languages except. They are very similar to Arrays and Objects, the key difference being that they are immutable, meaning they can't be updated or changed. They give us a brand new primitive type in Javascript, and let us do a lot of things we couldn't previously do, including comparing objects and arrays by value, rather than identity. In this article, we'll cover how they work, and how you can use them today.

    Support for Records and Tuples

    Currently, records and tuples are a stage 2 proposal for Javascript. Broadly speaking, this means that they are relatively stable, but not implemented as a standard spec. As such, major browsers and backend Javascript like Node.JS do not implement them. You can, however, use them, if you have Babel, by using this polyfill.

    What are Records and Tuples in Javascript?

    Records and Tuples introduce a brand new primitive type to Javascript, but ultimately follow the same syntax as Objects and Arrays. When we want to define a new Record or Tuple, we use the syntax #{} or #[]. As such, we can define both as shown in the code below: let myRecord = #{ name: "New Record", tags: #['some', 'tags', 'go', 'here'] } let myTuple = #['some', 'other', 'set', 'of', 'array', 'items']; As you can see, the syntax is identical to objects and arrays, with the exception of the hash (#) at the start. Note, that we can also put a Tuple in our Record, as shown in the first example.

    Records and Tuples are immutable

    Both Records and Tuples in Javascript are deeply immutable. All that means is that they can't be changed, at any level. If you try to change them, you'll get an error: let myRecord = #{ name: "New Record", tags: #['some', 'tags', 'go', 'here'] } myRecord.name = 'Another Record'; // This will throw an error That also means you can't insert something new into them. In that way, they act as a source of truth - which brings us onto their main use case. Both Tuples and Records allow us to compare Objects and Arrays based on their value, rather than their identity.

    Records and Tuples compare Values, not Identity

    If you try to run the following code, you'll get false back: console.log({ a: 1 } === { a: 1 }) // returns false console.log([1, 2, 3] === [1, 2, 3]) // returns false That might be confusing, but it's because equality of Objects and Arrays work on the basis of identity. When we define a new Object or Array, it is given a unique identity. As such, when comparing the identity of two different Objects, the result is false. Records and Tuples break that convention, and allow us to compare by value. Deep comparisons of objects has been something that's been quite tricky in Javascript for a long time, but with Tuples and Records we can finally do that. As such, the following code returns true: console.log(#{ a: { b : 3 }} === #{ a: { b : 3 }}) // return true console.log(#[1, 2, 3] === #[1, 2, 3]) // returns true This means we can finally (and easily) make comparisons of the value between different objects, where we expect a very specific return value.

    Converting Arrays to Tuples and Objects to Records in Javascript

    Since Records and Tuples are compared by value, you may want to convert regular Objects and Arrays into them, so that you can make that comparison. Fortunately, we can convert any Object or Array into a Record or Tuple using Record() and Tuple(): let newRecord = Record({ a: 1, b: 2 }); let newTuple = Tuple(...[1, 2, 3, 4, 5]); let anotherTuple = Tuple.from([1, 2, 3, 4, 5]); Both the above lines will produce the Record and Tuple version of each. Future proposals also include a JSON.parseImmutable function, which will let us convert strings of Arrays or Objects straight into their Tuple or Record form. This is not currently implemented.

    Adding to a Tuple or Record

    I am aware that I have just said that you can't add to or change a Tuple/Record - but you can produce a new Tuple or Record based on an old one. This will be a totally different Tuple/Record - but it will use the data from the old and add something new. We can do that as shown below: let myTuple = #[1, 2, 3, 4, 5]; let myRecord = #{ a: 1, b: 1 }; // Produce a new record using original myRecord: let newRecord = #{ ...myRecord, c: 1 } // #{ a: 1, b: 1, c: 1} // Produce a new tuple using myTuple: let newTuple = #[ ...myTuple, 6, 7]; // Or you can use Tuple.with(): let anotherTuple = myTuple.with(6, 7);

    Interacting with Tuples and Records in Javascript

    Tuples and Records work exactly the same as Objects and Arrays except they cannot be changed. As such, you can iterate through them, or interact with them using the same methods as are available on Objects and Arrays. For example, we could get all the keys of a particular Record: let myRecord = #{ a: 1, b: 2, c: 2}; let recordKeys = Object.keys(myRecord); // Returns ['a', 'b', 'c']; Or you could iterate over an array using a for loop: let myTuple = #[1, 2, 3, 4, 5]; for(const i of myTuple) { console.log(i); } // Console logs 1, 2, 3, 4, 5 on after each other

    Conclusion

    As Tuples and Records aren't widely supported, you will need the Babel polyfill to use them. They allow us to compare data from Objects and Arrays in ways we couldn't before, making code much simpler where it once required complicated custom functions.

    filter null values from array

    let array = [0, 1, null, 2, 3]; function removeNull(array) { return array.filter(x => x !== null) };

    equivalent of http-equiv redirect

    use window.location.reload() to refresh use setTimeout(function() { window.location.reload(); }, 35000); to fire after 35 seconds use either window.location.replace('http://www.example.com') To redirect to another page make sure the browser Back button skips the previous page, or window.location = 'http://www.example.com' to preserve the browser history.

    access dom img src

    topicId = "topic-" + topicpointer document.getElementById([topicId]).attributes.length; // indirect access document.getElementById([topicId]).attributes document.getElementById([topicId]).attributes[3] document.getElementById([topicId]).attributes.src imgSrc = document.getElementById([topicId]).attributes.src.nodeValue window.open(imgSrc);

    indirect pointer

    console.log(`My name is ${topicId}`); console.log('${topicId}'); javascript substitute value of variable var name = "javascript"; console.log(`My name is ${name}`); // My name is javascript

    access href.text

    window.location.href.text()

    slide show

    <img name="slide"> <script> var i = 0; // Start Point var time = 3000; // Time Between Switch // Image List images = [ "https://cdnimgzh.vietnamplus.vn/t870/uploaded/zokttb/2021_11_17/1_1.jpg", "https://cdnimgzh.vietnamplus.vn/t870/uploaded/zokttb/2021_11_17/2avatar.jpg", "https://cdnimgzh.vietnamplus.vn/t870/uploaded/zokttb/2021_11_17/3_1.jpg", "https://cdnimgzh.vietnamplus.vn/t870/uploaded/zokttb/2021_11_17/4.jpg", ] // Change Image function changeImg(){ document.slide.src = images[i]; // element name is slide if(i < images.length - 1){ // Check If Index Is Under Max i++; // Add 1 to Index } else { i = 0; // Reset Back To O } setTimeout("changeImg()", time); // Run function every x seconds } window.onload=changeImg; // Run function when page loads </script>

    to pass variable in querySelector function()

    https://www.codegrepper.com/code-examples/javascript/how+to+pass+variable+in+querySelector+function%28%29 querySelector with very long selector document.querySelector('#site-modal > div > div > div > div.modal-body.bb-modal-body-tiled.pb-0 > div:nth-child(3) > div > section > div.bb-tile-content > div > div:nth-child(2) > div > div.collapse.toggleinfo > div:nth-child(5) > div.col-xs-6 > a').outerHTML (variableInBROWSER => { return document.querySelector(variableInBROWSER).innerHTML}; ); // This selects the first element with that name document.querySelector('[name="your-selector-name-here"]');

    scroll to bottom of div

    // To scroll to the bottom of a div const theElement = document.getElementById('elementID'); const scrollToBottom = (node) => { node.scrollTop = node.scrollHeight; } scrollToBottom(theElement); // The specified node scrolls to the bottom. // without smooth-scroll const scrollToBottom = () => { divRef.current.scrollTop = divRef.current.scrollHeight; }; //with smooth-scroll const scrollToBottomWithSmoothScroll = () => { divRef.current.scrollTo({ top: divRef.current.scrollHeight, behavior: 'smooth', }) } scrollToBottom() scrollToBottomWithSmoothScroll() //scroll to the bottom of "#myDiv" var myDiv = document.getElementById("myDiv"); myDiv.scrollTop = myDiv.scrollHeight; //scroll to the bottom of "#myDiv" $("#mydiv").scrollTop($("#mydiv")[0].scrollHeight);

    new JavaScript language features



    String.prototype.replaceAll

    The replaceAll() method takes a string or regular expression, called the pattern, as its first argument. The second argument is the pattern's replacement. Given the first and second argument, replaceAll() returns a new string that will be the source string with all instances of the pattern swapped for the replacement. The source string is not affected.In ECMAScript 2021, replaceAll() joins ECMAScript 2020’s matchAll() in improving the inherent capabilities of JavaScript’s built-in String object.The replaceAll() method works exactly like replace(), but applies to all occurrences in the string, instead of just the first one. It’s a welcome addition after years of having to use a library or hand-coded solution. Listing 1 shows a simple example, wherein we mangle some Shakespeare.

    Listing 1. replaceAll()

    let quote = "all the world's a stage, and all the men and women merely players"; let newQuote = quote.replaceAll("all", "most of"); console.log(newQuote);

    promise.any()

    The promise.any() method takes a collection of promises and allows you to respond to the first one that completes successfully by returning a new promise. If any promises are rejected, they are ignored. (Note this method's contrast with promise.all(), which stops with any error or rejection; and with promise.allSettled(), which lets you observe all promises that resolved in a collection, even if there were intervening errors.) If any of the promises error out, promise.any() will still act upon the first resolved promise in the collection. The promise.any() method returns a rejected promise if none of the passed-in promises resolves. The error it returns is AggregateError, which is a new error type also introduced by ECMAScript 2021. AggregateError represents the summary of all errors encountered.You can use promise.any() to roll up many promises into a single one. This promise will resolve to whichever of the collection resolves first, ignoring errors and rejections. Listing 2 has a simple example.

    Listing 2. promise.any()—all resolved

    const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 1000, "1 second"); }); const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 2000, "2 second"); }); let promises = [promise1, promise2]; Promise.any(promises).then((firstResolved) => { console.log(firstResolved); // outputs “1 second” }) Now consider Listing 3, wherein all promises eventually fail as rejected.

    Listing 3. promise.any()—all rejected

    const promise1 = new Promise((resolve, reject) => { setTimeout(reject, 1000, "1 second"); }); const promise2 = new Promise((resolve, reject) => { setTimeout(reject, 2000, "2 second"); }); let promises = [promise1, promise2]; Promise.any(promises).then((firstResolved) => { console.log(firstResolved); }).catch((err) => { console.log("error: " + err) }) // outputs error: AggregateError: All promises were rejected In Listing 3, we add a catch handler, which fires after both promises are rejected. Notice that AggregateError is an object holding information about the failed promises. Let's get a closer look at AggregateError, which is another new feature in ECMAScript 2021.

    AggregateError

    AggregateError is a special kind of error subclass that combines many errors into a summary object. As you saw, the promise.any() method in Listing 3 created an AggregateError.In that example, all promises passed to promise.any() failed, so the method returned an AggregateError. The error contained a message describing the error and an array with details about each error. Listing 4 shows the contents of the error returned.

    Listing 4. AggregateError

    AggregateError: All promises were rejected errors: Array(2) 0: "1 second" 1: "2 second" length: 2 message: "All promises were rejected" stack: "AggregateError: All promises were rejected" As shown, AggregateError gives you access to the promise messages that contributed to the error, via AggregateError.errors.

    New logical assignment operators

    JavaScript has familiar math assignment operators such as +=, which perform the operation and assignment in one go, as a kind of convenience. ECMAScript 2021 adds similar support to the logical operators ||, ??, and &&.Let’s take a look at each of these.

    Nullish assignment (??=)

    You can use the nullish assignment operator to test a variable for being null or undefined. If the variable is null or undefined, you can assign the right side of the expression to the variable. Listing 5 is an example.

    Listing 5. The ??= assignment in action

    let quote = "When goodness is lost there is morality."; let existingQuote = "A leader is best when people barely know he exists"; let nonExistingQuote = null; existingQuote ??= quote; nonExistingQuote ??= quote; console.log(existingQuote); // A leader is best when people barely know he exists console.log(nonExistingQuote); // When goodness is lost there is morality. Notice that when used on a variable that exists, like existingQuote, the nullish assignment operator does nothing. When used on nonExistingQuote, however, it assigns the quote a new value. Even if the string were empty for existingQuote (which is a falsy value in JavaScript), the nullish assignment will not replace it; it will remain an empty string. That is the essence of the operator: it only tests for null or undefined.

    And assignment (&&=)

    The and assignment operator (&&=) tests the left side of an expression. If the left side is truthy, it assigns the right side of the expression. If it is falsy, the operator does nothing. Listing 6 shows a simple example.

    Listing 6. The &&= assignment in action

    let emptyString = ""; emptyString &&= "bar"; console.log (emptyString); // “” let nonEmptyString = "foo"; nonEmptyString &&= "bar"; console.log(nonEmptyString); // “bar” In Listing 6, the first console log outputs an empty string. This is because the empty string is falsy, so the &&= operator does not assign it a new value. The second console outputs "bar". This is because nonEmptyString is “foo”, which is a truthy value.&&= is a kind of edge case operator, but useful when you need it.

    Or assignment (||=)

    The or assignment operator is the opposite of the and assignment operator you just saw. We can use the same example from Listing 6, this time replacing &&= with ||=.

    Listing 7. The ||= assignment in action

    let emptyString = ""; emptyString ||= "bar"; console.log (emptyString); // “bar” let nonEmptyString = "foo"; nonEmptyString ||= "bar"; console.log(nonEmptyString); // “foo” If the left side of the expression is falsy, the ||= assignment operator resolves to the right side. Therefore, in this case, the emptyString becomes “bar”. The nonEmptyString variable stays with its truthy value of “foo”.

    WeakRef

    WeakRef is used to refer to a target object without preserving it from garbage collection. It is a rather esoteric language feature, not much used by the working coder. The one common use case for WeakRef is in implementing caches or mappings for large objects, "where it’s desired that a large object is not kept alive solely because it appears in a cache or mapping.”So, if you find yourself building a caching solution for large entities, remember that WeakRef exists. Otherwise, if you are not sure about needing a WeakRef variable reference, you probably should avoid using it. (The spec itself recommends avoidance.)

    FinalizationRegistry

    It is a bit of programming irony that JavaScript introduced FinalizationRegistry almost simultaneously with Java’s deprecation of Object.finalize(). The features are practically analogous. Like WeakRef, the specification warns developers away from user-defined finalizers. For some use cases, however, the new FinalizationRegistry could be just what you need. The specification offers the example of long-running processes consuming many file handles. In such a case, using FinalizationRegistry could ensure no handles are leaked.Along with WeakRef, FinalizationRegistry fits better into the toolbox of platform and framework developers, rather than application developers.

    Numeric literal separators

    Numeric separators are a nicety that make looking at large number easier on the eyes. JavaScript can’t use commas like natural languages, because that symbol is already taken. So, ECMAScript 2021 introduced the underscore.Instead of typing let distanceToSun = 91772000000; you can type let distanceToSun = 91_772_000_000; The new form is quite a bit easier to read.

    The Definition element

    The HTML element is used to indicate the term being defined within the context of a definition phrase or sentence. The element, the <dt>/<dd> pairing, or the element which is the nearest ancestor of the is considered to be the definition of the term. A validator is a program that checks for syntax errors in code or documents.

    window[className]

    // Would only work in browsers, not NodeJS let className = "Paintbrush"; console.log( window[className] );

    Big.js tutorial



    Big.js tutorial shows how to work with arbitrary precision big decimal arithmetic in JavaScript with Big.js module.

    Big.js

    Big.js is a small, fast JavaScript library for arbitrary-precision decimal arithmetic. In this article we work with Big.js in a Node application.

    Setting up Big.js

    First, we install Big.js. $ node -v v18.2.0 We use Node version 18.2.0. $ npm init -y We initiate a new Node application. $ npm i big.js We install Big.js with npm i big.js command.

    JavaScript Number precision error

    In the first example, we show that JavaScript Numbers are not precise for doing arbitrary precision arithmetic. count_currency.js var sum = 0; // two euros fifty-five cents var amount = 2.55; for (let i = 0; i < 100000; i++) { sum += amount; } console.log(sum); In the example, we add two euros fifty-five cents one hundred thousand times. $ nodejs numbers.js 254999.9999995398 We have an error in the calculation.

    Big.js example

    In the next example we correct the error with Big.js. main.js import Big from 'big.js'; let val = new Big(0.0); let amount = new Big(2.55); let sum = val.plus(amount).times(100000); console.log(sum.toFixed(2)); With Big.js library, the calculation is precise. import Big from 'big.js'; We import Big from the big.js module. let val = new Big(0.0); let amount = new Big(2.55); We create two big decimal values. let sum = val.plus(amount).times(100000); We add the value 100000 times. Note that the big decimal values are immutable, so we generate a new variable. $ node main.js 255000.00

    Big.js pow

    The pow provides a high-precision power operation. main.js import Big from 'big.js'; let val = new Big(0.9); let res = val.pow(3); console.log(res); console.log(0.9 ** 3); The example raises the 0.9 to the power of 3 using Big.js and vanilla JS. $ node main.js 0.729 0.7290000000000001 In this article, we have worked with arbitrary precision arithmetic in JavaScript with the Big.js library.

    Classes



    https://www.w3schools.com/js/js_classes.asp

    JavaScript Class Syntax

    Use the keyword class to create a class. Always add a method named constructor(): A JavaScript class is not an object. It is a template for JavaScript objects. Syntax class ClassName { constructor() { ... } } Example class Car { constructor(name, year) { this.name = name; this.year = year; } } The example above creates a class named "Car". The class has two initial properties: "name" and "year".

    Using a Class

    When you have a class, you can use the class to create objects: Example let myCar1 = new Car("Ford", 2014); let myCar2 = new Car("Audi", 2019); The example above uses the Car class to create two Car objects. The constructor method is called automatically when a new object is created.

    The Constructor Method

    The constructor method is a special method: It has to have the exact name "constructor" It is executed automatically when a new object is created It is used to initialize object properties If you do not define a constructor method, JavaScript will add an empty constructor method.

    Class Methods

    Class methods are created with the same syntax as object methods. Use the keyword class to create a class. Always add a constructor() method. Then add any number of methods. Syntax class ClassName { constructor() { ... } method_1() { ... } method_2() { ... } method_3() { ... } } Create a Class method named "age", that returns the Car age: class Car { constructor(name, year) { this.name = name; this.year = year; } age() { let date = new Date(); return date.getFullYear() - this.year; } } let myCar = new Car("Ford", 2014); document.getElementById("demo").innerHTML = "My car is " + myCar.age() + " years old."; You can send parameters to Class methods: class Car { constructor(name, year) { this.name = name; this.year = year; } age(x) { return x - this.year; } } let date = new Date(); let year = date.getFullYear(); let myCar = new Car("Ford", 2014); document.getElementById("demo").innerHTML="My car is " + myCar.age(year) + " years old.";

    Convert Array to String Without Commas

    .join method arr.join("")

    join() Method With Blank Value or Blank Space

    array.join(separator) let array = ['Le', 'sn', 'er']; let join = array.join(""); // 'Lesner' join() Method With Blank Space let array = ['Linux', 'hint']; let join = array.join(" "); // 'Linux hint'

    Using pop() and push() Methods

    array.push(item1, item2) the "array.pop()" method extracts the added elements from an array. let array = ['Script', 'va', 'Ja'] let arrayNew = [] a=array.pop(0) // 'Ja' b=array.pop(1) // 'va' c=array.pop(2) // 'Script' arrayNew.push(a, b, c) let join = arrayNew.join("")

    the Combination of split() Method and join()

    The "split()" method splits a string into a substring array. This method can be used along with the "join()" method to split the commas in the joined string values by formatting them to comma-separated merged string values. string.split(separator, limit) let array = ['We,b', 'si,te']; let arrayNew = [] let join = array.join(''); // 'We,bsi,te' let join2 = join.split(",").join('') // 'Website'

    Global Methods and Properties

    NameDescription
    decodeURI()Decodes a URI
    decodeURI Component()Decodes a URI component
    encodeURI()Encodes a URI
    encodeURI Component()Encodes a URI component
    escape()Deprecated. Use instead: encodeURI() encodeURIComponent()
    eval()Evaluates a string and executes it as if it was script code
    InfinityA numeric value that represents positive/negative infinity
    isFinite()Determines whether a value is a finite, legal number
    isNaN()Determines whether a value is an illegal number
    NaN"Not-a-Number" value
    Number()Converts an object\'s value to a number
    parseFloat()Parses a string and returns a floating point number
    parseInt()Parses a string and returns an integer
    String()Converts an object\'s value to a string
    undefinedIndicates that a variable has not been assigned a value
    unescape()Deprecated. Use instead: decodeURI() decodeURIComponent()

    Note

    Since these methods are global, and global the object is the browser window, these methods are actually window methods: isNaN() is the same as window.isNaN().

    select multiple array elements

    var myArray = ["a", "b", "c", "d", "e", "f"]; var myIndices = [0, 2, 4, 6, 8]; var result = []; myIndices.forEach(i => result.push(myArray[i]));

    You cannot query html pseudo-elements with jQuery

    to clone an array in JavaScript

    When we need to copy an array, we often times used slice. const sheeps = ['🐑', '🐑', '🐑']; // Old way const cloneSheeps = sheeps.slice(); // ES6 way const cloneSheepsES6 = [...sheeps]; numbers = [1, 2, 3]; numbersCopy = [...numbers]; Note: This doesn’t safely copy multi-dimensional arrays. Array/object values are copied by reference instead of by value. Don't Use = to Copy an Array Because arrays in JS are reference values, so when you try to copy it using the = it will only copy the reference to the original array and not the value of the array. To create a real copy of an array, you need to copy over the value of the array under a new value variable. That way this new array does not reference to the old array address in memory.

    AngularJS Tutorial

    ♦AngularJS Tutorial for Beginners ♦AngularJSTutorial ♦AngularJS Tutorial ♦AngularJS References AngularJS Examples AngularJs Examples
    AngularJS Angular 2 ♦Tutorialspoint Angularjs Tutorial

    追風4.html init code

    //var thecode = localStorage.stkCode; if (localStorage.getItem("fourcodes") === null) { localStorage.setItem("fourcodes", "110000,110010,000001.sh,399001.sz") thecodes = "110000,110010,000001.sh,399001.sz" } else{ thecodes = localStorage.getItem("fourcodes").split(",") } if (localStorage.getItem("ImgPCode") === null) { localStorage.setItem("ImgPCode", "&period=5000") thisImgPCode = "&period=5000"; } else{ thisImgPCode = localStorage.getItem("ImgPCode"); } if (localStorage.getItem("trendBase") === null) { localStorage.setItem("trendBase", 10) trendBase = 10; } else{ trendBase = Number(localStorage.getItem("trendBase")) } if (localStorage.getItem("chaseWindTime") === null) { localStorage.setItem("chaseWindTime", 20000) chaseWindTime = 20000; } else{ chaseWindTime = Number(localStorage.getItem("chaseWindTime")) }

    convert a string to a number

    using the unary plus operator (+) quantity = "12"; +quantity convert array of string to a number var arr = ["1", "2", "3"]; var nums = arr.map(unaryOp); // Function that converts string to number function unaryOp(value) { return +value; }

    jQuery get the image src

    $('.class').find('tag').attr('src');

    前端实现电子签名(web、移动端)通用组件

    前言

    在现在的时代发展中,从以前的手写签名,逐渐衍生出了电子签名。 电子签名和纸质手写签名一样具有法律效应。 电子签名目前主要还是在需要个人确认的产品环节和司法类相关的产品上较多。 举个常用的例子,大家都用过钉钉,钉钉上面就有电子签名,相信大家这肯定是知道的。 那作为前端的我们如何实现电子签名呢? 其实在html5中已经出现了一个重要级别的辅助标签,是啥呢? 那就是canvas[1]

    什么是canvas

    Canvas(画布)是在HTML5中新增的标签用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript操作的位图(bitmap)Canvas 对象表示一个 HTML 画布元素 -。 它没有自己的行为,但是定义了一个 API 支持脚本化客户端绘图操作。 大白话就是canvas是一个可以在上面通过javaScript画图的标签,通过其提供的context(上下文)Api进行绘制,在这个过程中canvas充当画布的角色。 <canvas></canvas>

    如何使用

    canvas给我们提供了很多的Api,供我们使用,我们只需要在body标签中创建一个canvas标签,在script标签中拿到canvas这个标签的节点,并创建context(上下文)就可以使用了。 ...<body><canvas></canvas></body><script>//获取canvas实例constcanvas=document.querySelector('canvas')canvas.getContext('2d')</script>...步入正题。

    实现电子签名

    知道几何的朋友都很清楚,线有点绘成,面由线绘成。 多点成线,多线成面。 所以我们实际只需要拿到当前触摸的坐标点,进行成线处理就可以了。

    body中添加canvas标签

    在这里我们不仅需要在在body中添加canvas标签,我们还需要添加两个按钮,分别是取消保存(后面我们会用到)。 <body><canvas></canvas><div><button>取消</button><button>保存</button></div></body>

    添加文件

    我这里全程使用js进行样式设置及添加。 //配置内容constconfig={width:400,//宽度height:200,//高度lineWidth:5,//线宽strokeStyle:'red',//线条颜色lineCap:'round',//设置线条两端圆角lineJoin:'round',//线条交汇处圆角}

    获取canvas实例

    这里我们使用querySelector获取canvas的dom实例,并设置样式和创建上下文。 //获取canvas实例constcanvas=document.querySelector('canvas')//设置宽高canvas.width=config.widthcanvas.height=config.height//设置一个边框,方便我们查看及使用canvas.style.border='1pxsolid#000'//创建上下文constctx=canvas.getContext('2d')

    基础设置

    我们将canvas的填充色为透明,并绘制填充一个矩形,作为我们的画布,如果不设置这个填充背景色,在我们初识渲染的时候是一个黑色背景,这也是它的一个默认色。 //设置填充背景色ctx.fillStyle='transparent'//绘制填充矩形ctx.fillRect(0,//x轴起始绘制位置0,//y轴起始绘制位置config.width,//宽度config.height//高度);

    上次绘制路径保存

    这里我们需要声明一个对象,用来记录我们上一次绘制的路径结束坐标点及偏移量。 保存上次坐标点这个我不用说大家都懂; 为啥需要保存偏移量呢,因为鼠标和画布上的距离是存在一定的偏移距离,在我们绘制的过程中需要减去这个偏移量,才是我们实际的绘制坐标。 但我发现chrome中不需要减去这个偏移量,拿到的就是实际的坐标,之前在微信小程序中使用就需要减去偏移量,需要在小程序中使用的朋友需要注意这一点哦。 //保存上次绘制的坐标及偏移量constclient={offsetX:0,//偏移量offsetY:0,endX:0,//坐标endY:0}

    设备兼容

    我们需要它不仅可以在web端使用,还需要在移动端使用,我们需要给它做设备兼容处理。 我们通过调用navigator.userAgent获取当前设备信息,进行正则匹配判断。 //判断是否为移动端constmobileStatus=(/Mobile|Android|iPhone/i.test(navigator.userAgent))

    初始化

    这里我们在监听鼠标按下(mousedown)(web端)/触摸开始(touchstart)的时候进行初始化,事件监听采用addEventListener//创建鼠标/手势按下监听器window.addEventListener(mobileStatus?"touchstart":"mousedown",init)三元判断说明: 这里当mobileStatustrue时则表示为移动端,反之则为web端,后续使用到的三元依旧是这个意思。 声明初始化方法我们添加一个init方法作为监听鼠标按下/触摸开始的回调方法。 这里我们需要获取到当前鼠标按下/触摸开始的偏移量和坐标,进行起始点绘制。 Tips: web端可以直接通过event中取到,而移动端则需要在event.changedTouches[0]中取到。 这里我们在初始化后再监听鼠标的移动。 //初始化constinit=event=>{//获取偏移量及坐标const{offsetX,offsetY,pageX,pageY}=mobileStatus?event.changedTouches[0]:event//修改上次的偏移量及坐标client.offsetX=offsetXclient.offsetY=offsetYclient.endX=pageXclient.endY=pageY//清除以上一次beginPath之后的所有路径,进行绘制ctx.beginPath()//根据配置文件设置进行相应配置ctx.lineWidth=config.lineWidthctx.strokeStyle=config.strokeStylectx.lineCap=config.lineCapctx.lineJoin=config.lineJoin//设置画线起始点位ctx.moveTo(client.endX,client.endY)//监听鼠标移动或手势移动window.addEventListener(mobileStatus?"touchmove":"mousemove",draw)}

    绘制

    这里我们添加绘制draw方法,作为监听鼠标移动/触摸移动的回调方法。 //绘制constdraw=event=>{//获取当前坐标点位const{pageX,pageY}=mobileStatus?event.changedTouches[0]:event//修改最后一次绘制的坐标点client.endX=pageXclient.endY=pageY//根据坐标点位移动添加线条ctx.lineTo(pageX,pageY)//绘制ctx.stroke()}

    结束绘制

    添加了监听鼠标移动/触摸移动我们一定要记得取消监听并结束绘制,不然的话它会一直监听并绘制的。 这里我们创建一个cloaseDraw方法作为鼠标弹起/结束触摸的回调方法来结束绘制并移除鼠标移动/触摸移动的监听。 canvas结束绘制则需要调用closePath()让其结束绘制//结束绘制constcloaseDraw=()=>{//结束绘制ctx.closePath()//移除鼠标移动或手势移动监听器window.removeEventListener("mousemove",draw)}添加结束回调监听器//创建鼠标/手势弹起/离开监听器window.addEventListener(mobileStatus?"touchend":"mouseup",cloaseDraw)ok,现在我们的电子签名功能还差一丢丢可以实现完了,现在已经可以正常的签名了。 我们来看一下效果:

    取消功能/清空画布

    我们在刚开始创建的那两个按钮开始排上用场了。 这里我们创建一个cancel的方法作为取消并清空画布使用//取消-清空画布constcancel=()=>{//清空当前画布上的所有绘制内容ctx.clearRect(0,0,config.width,config.height)}然后我们将这个方法和取消按钮进行绑定<buttononclick="cancel()">取消</button>

    保存功能

    这里我们创建一个save的方法作为保存画布上的内容使用。 将画布上的内容保存为图片/文件的方法有很多,比较常见的是blobtoDataURL这两种方案,但toDataURL这哥们没blob强,适配也不咋滴。 所以我们这里采用a标签 ➕ blob方案实现图片的保存下载。 //保存-将画布内容保存为图片constsave=()=>{//将canvas上的内容转成blob流canvas.toBlob(blob=>{//获取当前时间并转成字符串,用来当做文件名constdate=Date.now().toString()//创建一个a标签consta=document.createElement('a')//设置a标签的下载文件名a.download=`${date}.png`//设置a标签的跳转路径为文件流地址a.href=URL.createObjectURL(blob)//手动触发a标签的点击事件a.click()//移除a标签a.remove()})}然后我们将这个方法和保存按钮进行绑定<buttononclick="save()">保存</button>我们将刚刚绘制的内容进行保存,点击保存按钮,就会进行下载保存

    完整代码

    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title><style>*{margin:0;padding:0;}</style></head><body><canvas></canvas><div><buttononclick="cancel()">取消</button><buttononclick="save()">保存</button></div></body><script>//配置内容constconfig={width:400,//宽度height:200,//高度lineWidth:5,//线宽strokeStyle:'red',//线条颜色lineCap:'round',//设置线条两端圆角lineJoin:'round',//线条交汇处圆角}//获取canvas实例constcanvas=document.querySelector('canvas')//设置宽高canvas.width=config.widthcanvas.height=config.height//设置一个边框canvas.style.border='1pxsolid#000'//创建上下文constctx=canvas.getContext('2d')//设置填充背景色ctx.fillStyle='transparent'//绘制填充矩形ctx.fillRect(0,//x轴起始绘制位置0,//y轴起始绘制位置config.width,//宽度config.height//高度);//保存上次绘制的坐标及偏移量constclient={offsetX:0,//偏移量offsetY:0,endX:0,//坐标endY:0}//判断是否为移动端constmobileStatus=(/Mobile|Android|iPhone/i.test(navigator.userAgent))//初始化constinit=event=>{//获取偏移量及坐标const{offsetX,offsetY,pageX,pageY}=mobileStatus?event.changedTouches[0]:event//修改上次的偏移量及坐标client.offsetX=offsetXclient.offsetY=offsetYclient.endX=pageXclient.endY=pageY//清除以上一次beginPath之后的所有路径,进行绘制ctx.beginPath()//根据配置文件设置相应配置ctx.lineWidth=config.lineWidthctx.strokeStyle=config.strokeStylectx.lineCap=config.lineCapctx.lineJoin=config.lineJoin//设置画线起始点位ctx.moveTo(client.endX,client.endY)//监听鼠标移动或手势移动window.addEventListener(mobileStatus?"touchmove":"mousemove",draw)}//绘制constdraw=event=>{//获取当前坐标点位const{pageX,pageY}=mobileStatus?event.changedTouches[0]:event//修改最后一次绘制的坐标点client.endX=pageXclient.endY=pageY//根据坐标点位移动添加线条ctx.lineTo(pageX,pageY)//绘制ctx.stroke()}//结束绘制constcloaseDraw=()=>{//结束绘制ctx.closePath()//移除鼠标移动或手势移动监听器window.removeEventListener("mousemove",draw)}//创建鼠标/手势按下监听器window.addEventListener(mobileStatus?"touchstart":"mousedown",init)//创建鼠标/手势弹起/离开监听器window.addEventListener(mobileStatus?"touchend":"mouseup",cloaseDraw)//取消-清空画布constcancel=()=>{//清空当前画布上的所有绘制内容ctx.clearRect(0,0,config.width,config.height)}//保存-将画布内容保存为图片constsave=()=>{//将canvas上的内容转成blob流canvas.toBlob(blob=>{//获取当前时间并转成字符串,用来当做文件名constdate=Date.now().toString()//创建一个a标签consta=document.createElement('a')//设置a标签的下载文件名a.download=`${date}.png`//设置a标签的跳转路径为文件流地址a.href=URL.createObjectURL(blob)//手动触发a标签的点击事件a.click()//移除a标签a.remove()})}</script></html>

    各内核和浏览器支持情况

    Mozilla 程序从 Gecko 1.8 (Firefox 1.5 \(en-US\)[2]) 开始支持 <canvas>。 它首先是由 Apple 引入的,用于 OS X Dashboard 和 Safari。 Internet Explorer 从 IE9 开始支持<canvas> ,更旧版本的 IE 中,页面可以通过引入 Google 的 Explorer Canvas[3] 项目中的脚本来获得<canvas>支持。 Google Chrome 和 Opera 9+ 也支持 <canvas>

    小程序中提示

    在小程序中我们如果需呀实现的话,也是同样的原理哦,只是我们需要将创建实例和上下文Api进行修改,因为小程序中是没有dom,既然没有dom,哪来的操作dom这个操作呢。 如果是uni-app则需要使用uni.createCanvasContext[4]进行上下文创建
  • 如果是原生微信小程序则使用`wx.createCanvasContext`[5]进行创建(2.9.0)之后的库不支持

    create tables

    <table id="this"></table> <table id="that"></table> <script> let food = [ { name: "meat", weight: 1658, percentage: 15 }, { name: "fish", weight: 1654, percentage: 12 } ]; let mountains = [ { name: "Monte Falco", height: 1658, place: "Parco Foreste Casentinesi" }, { name: "Monte Falterona", height: 1654, place: "Parco Foreste Casentinesi" }, { name: "Poggio Scali", height: 1520, place: "Parco Foreste Casentinesi" }, { name: "Pratomagno", height: 1592, place: "Parco Foreste Casentinesi" }, { name: "Monte Amiata", height: 1738, place: "Siena" } ]; function generateTableHead(table, data) { let thead = table.createTHead(); let row = thead.insertRow(); for (let key of data) { let th = document.createElement("th"); let text = document.createTextNode(key); th.appendChild(text); row.appendChild(th); } } function generateTable(table, data) { for (let element of data) { let row = table.insertRow(); for (key in element) { let cell = row.insertCell(); let text = document.createTextNode(element[key]); cell.appendChild(text); } } } let mountaintable = document.querySelector("table#that"); let data = Object.keys(mountains[0]); generateTableHead(mountaintable, data); generateTable(mountaintable, mountains); let foodtable = document.querySelector("table#this"); let fooddata = Object.keys(food[0]); generateTableHead(foodtable, fooddata); generateTable(foodtable, food);

    creates a table with 3 rows 2 cells

    using insertRow and insertCell: function tableCreate() { const body = document.body, tbl = document.createElement('table'); tbl.style.width = '100px'; tbl.style.border = '1px solid black'; for (let i = 0; i < 3; i++) { const tr = tbl.insertRow(); for (let j = 0; j < 2; j++) { if (i === 2 && j === 1) { break; } else { const td = tr.insertCell(); td.appendChild(document.createTextNode(`Cell I${i}/J${j}`)); td.style.border = '1px solid black'; if (i === 1 && j === 1) { td.setAttribute('rowSpan', '2'); } } } } body.appendChild(tbl); } tableCreate(); function addTable() { var myTableDiv = document.getElementById("myDynamicTable"); var table = document.createElement('TABLE'); table.border = '1'; var tableBody = document.createElement('TBODY'); table.appendChild(tableBody); for (var i = 0; i < 3; i++) { var tr = document.createElement('TR'); tableBody.appendChild(tr); for (var j = 0; j < 4; j++) { var td = document.createElement('TD'); td.width = '75'; td.appendChild(document.createTextNode("Cell " + i + "," + j)); tr.appendChild(td); } } myTableDiv.appendChild(table); } addTable();

    reduce 使用技巧

    reduce 函数可以根据需要进行累加、过滤、分组、映射等操作,是一个非常强大的数组方法。 在数据处理时使用的非常频繁,很多复杂的逻辑如果用reduce去处理,都非常的简洁,在实际的开发工作过程中,积累了一些常见又超级好用的 reduce 技巧的代码片段,筛选了如下 10 个,以供大家参考

    reduce 介绍

    reduce 是数组的方法,可以对数组中的每个元素依次执行一个回调函数,从左到右依次累积计算出一个最终的值。 其语法为: arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]) 其中,callback 是每个元素执行的回调函数,其包含 4 个参数: accumulator:累积器,即上一次回调函数执行的返回值。 currentValue:当前元素的值。 index:当前元素的下标。 array:原始数组。 initialValue 是可选的,表示累积器的初始值。 reduce 函数的执行过程如下: 如果没有提供 initialValue,则将数组的第一个元素作为累积器的初始值,否则将 initialValue 作为累积器的初始值。 从数组的第二个元素开始,依次对数组中的每个元素执行回调函数。 回调函数的返回值作为下一次回调函数执行时的累积器的值。 对数组中的每个元素执行完回调函数后,reduce 函数返回最后一次回调函数的返回值,即最终的累积值。

    计算数组中每个元素出现的次数

    const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']; const count = fruits.reduce((accumulator, currentValue) => { accumulator[currentValue] = (accumulator[currentValue] || 0) + 1; return accumulator; }, {}); console.log(count); // Output: { apple: 3, banana: 2, orange: 1 }

    拍平嵌套数组

    const nestedArray = [[1, 2], [3, 4], [5, 6]]; const flattenedArray = nestedArray.reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); console.log(flattenedArray); // Output: [1, 2, 3, 4, 5, 6]

    按条件分组

    const people = [ { name: 'Alice', age: 25 }, { name: 'Bob', age: 30 }, { name: 'Charlie', age: 35 }, { name: 'David', age: 25 }, { name: 'Emily', age: 30 } ]; const groupedPeople = people.reduce((accumulator, currentValue) => { const key = currentValue.age; if (!accumulator[key]) { accumulator[key] = []; } accumulator[key].push(currentValue); return accumulator; }, {}); console.log(groupedPeople); // Output: { // 25: [{ name: 'Alice', age: 25 }, { name: 'David', age: 25 }], // 30: [{ name: 'Bob', age: 30 }, { name: 'Emily', age: 30 }], // 35: [{ name: 'Charlie', age: 35 }] // }

    将多个数组合并为一个对象

    const keys = ['name', 'age', 'gender']; const values = ['Alice', 25, 'female']; const person = keys.reduce((accumulator, currentValue, index) => { accumulator[currentValue] = values[index]; return accumulator; }, {}); console.log(person); // Output: { name: 'Alice', age: 25, gender: 'female' }

    将字符串转换为对象

    const str = 'key1=value1&key2=value2&key3=value3'; const obj = str.split('&').reduce((accumulator, currentValue) => { const [key, value] = currentValue.split('='); accumulator[key] = value; return accumulator; }, {}); console.log(obj); // Output: { key1: 'value1', key2: 'value2', key3: 'value3' }

    将对象转换为查询字符串

    const params = { foo: "bar", baz: 42 }; const queryString = Object.entries(params).reduce((acc, [key, value]) => { return `${acc}${key}=${value}&`; }, "?").slice(0, -1); console.log(queryString); // "?foo=bar&baz=42"

    打印斐波那契数列

    const fibonacci = n => { return [...Array(n)].reduce((accumulator, currentValue, index) => { if (index < 2) { accumulator.push(index); } else { accumulator.push(accumulator[index - 1] + accumulator[index - 2]); } return accumulator; }, []); }; console.log(fibonacci(10)); // Output: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

    检查字符串是否是回文字符串

    const str = 'racecar'; const isPalindrome = str.split('').reduce((accumulator, currentValue, index, array) => { return accumulator && currentValue === array[array.length - index - 1]; }, true); console.log(isPalindrome); // Output: true

    检查括号是否匹配

    const str = "(()()())"; const balanced = str.split("").reduce((acc, cur) => { if (cur === "(") { acc++; } else if (cur === ")") { acc--; } return acc; }, 0) === 0; console.log(balanced); // true

    递归获取对象属性

    const user = { info: { name: "Jason", address: { home: "Shaanxi", company: "Xian" }, }, }; function get(config, path, defaultVal) { return path.split('.').reduce((config, name) => config[name], config) || defaultVal; return fallback; } get(user, "info.name"); // Jason get(user, "info.address.home"); // Shaanxi get(user, "info.address.company"); // Xian get(user, "info.address.abc", "default"); // default

    手写 reduce

    可以通过手写一个简单的 reduce 函数来更好地理解它的实现原理: function myReduce(arr, callback, initialValue) { let accumulator = initialValue === undefined ? arr[0] : initialValue; for (let i = initialValue === undefined ? 1 : 0; i < arr.length; i++) { accumulator = callback(accumulator, arr[i], i, arr); } return accumulator; } 上面的代码中,myReduce 函数接受 3 个参数:要执行 reduce 操作的数组 arr、回调函数 callback 和累积器的初始值 initialValue。 如果没有提供初始值,则将数组的第一个元素作为累积器的初始值。 接下来,在循环中,如果有 initialValue,则从第一个元素开始遍历 callback,此时 callabck 的第二个参数是从数组的第一项开始的; 如果没有 initialValue,则从第二个元素开始遍历 callback,此时 callback 的第二个参数是从数组的第二项开始的从数组的第二个元素开始,依次对数组中的每个元素执行回调函数,并将返回值作为下一次回调函数执行时的累积器的值。 最后,myReduce 函数返回最后一次回调函数的返回值,即最终的累积值。 这个简易的 reduce 函数并没有考虑很多边界情况和复杂的应用场景,但是可以帮助我们更好地理解 reduce 函数的实现原理。

    不喜欢用 forEach

    原因一:不支持处理异步函数

    先看一个例子: async function test() { let arr = [3, 2, 1] arr.forEach(async item => { const res = await mockSync(item) console.log(res) }) console.log('end') } function mockSync(x) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(x) }, 1000 * x) }) } test() 我们期望的结果是: 3 2 1 end 但是实际上会输出: end 1 2 3 JavaScript 中的forEach() 方法是一个同步方法,它不支持处理异步函数。 如果你在forEach 中执行了异步函数,forEach() 无法等待异步函数完成,它会继续执行下一项。 这意味着如果在forEach() 中使用异步函数,无法保证异步任务的执行顺序。

    替代forEach 的方式

    1.方式一 可以使用例如map() 、filter() 、reduce() 等,它们支持在函数中返回Promise ,并且会等待所有Promise完成。 使用map() 和Promise.all() 来处理异步函数的示例代码如下: const arr = [1, 2, 3, 4, 5]; async function asyncFunction(num) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(num * 2); }, 1000); }); } const promises = arr.map(async (num) => { const result = await asyncFunction(num); return result; }); Promise.all(promises).then((results) => { console.log(results); // [2, 4, 6, 8, 10] }); 由于我们在异步函数中使用了await 关键字,map() 方法会等待异步函数完成并返回结果,因此我们可以正确地处理异步函数。 方式二 使用for循环来处理异步函数 const arr = [1, 2, 3, 4, 5]; async function asyncFunction(num) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(num * 2); }, 1000); }); } async function processArray() { const results = []; for (let i = 0; i < arr.length; i++) { const result = await asyncFunction(arr[i]); results.push(result); } console.log(results); // [2, 4, 6, 8, 10] } processArray();

    原因二:无法捕获异步函数中的错误

    如果异步函数在执行时抛出错误,forEach() 无法捕获该错误。 这意味着即使在异步函数中出现错误,forEach() 仍会继续执行。

    原因三:除了抛出异常以外,没有办法中止或跳出 forEach() 循环

    forEach() 方法不支持使用break 或continue 语句来跳出循环或跳过某一项。 如果需要跳出循环或跳过某一项,应该使用for 循环或其他支持break 或continue 语句的方法。

    原因四:forEach 删除自身元素,index不可被重置

    在forEach 中我们无法控制 index 的值,它只会无脑的自增直至大于数组的 length 跳出循环。 所以也无法删除自身进行index重置,先看一个简单例子: let arr = [1,2,3,4] arr.forEach((item, index) => { console.log(item); // 1 2 3 4 index++; });

    原因五:this指向问题

    在forEach() 方法中,this 关键字引用的是调用该方法的对象。 但是,在使用普通函数或箭头函数作为参数时,this 关键字的作用域可能会出现问题。 在箭头函数中,this关键字引用的是定义该函数时所在的对象。 在普通函数中,this关键字引用的是调用该函数的对象。 如果需要确保this关键字的作用域正确,可以使用bind()方法来绑定函数的作用域。 以下是一个关于forEach() 方法中this 关键字作用域问题的例子: const obj = { name: "Alice", friends: ["Bob", "Charlie", "Dave"], printFriends: function() { this.friends.forEach(function(friend) { console.log(this.name + " is friends with " + friend); }); }, }; obj.printFriends(); 在这个例子中,我们定义了一个名为obj 的对象,它有一个printFriends() 方法。 在printFriends() 方法中,我们使用forEach() 方法遍历friends 数组,并使用普通函数打印每个朋友的名字和obj 对象的name 属性。 但是,当我们运行这个代码时,会发现输出结果为: undefined is friends with Bob undefined is friends with Charlie undefined is friends with Dave 这是因为,在forEach() 方法中使用普通函数时,该函数的作用域并不是调用printFriends() 方法的对象,而是全局作用域。 因此,在该函数中无法访问obj 对象的属性。 为了解决这个问题,可以使用bind() 方法来绑定函数的作用域,或使用箭头函数来定义回调函数。 以下是使用bind() 方法解决问题的代码示例: const obj = { name: "Alice", friends: ["Bob", "Charlie", "Dave"], printFriends: function() { this.friends.forEach( function(friend) { console.log(this.name + " is friends with " + friend); }.bind(this) // 使用bind()方法绑定函数的作用域 ); }, }; obj.printFriends(); 在这个例子中,我们使用bind() 方法来绑定函数的作用域,将该函数的作用域绑定到obj 对象上。 运行代码后,输出结果为: Alice is friends with Bob Alice is friends with Charlie Alice is friends with Dave 通过使用bind() 方法来绑定函数的作用域,我们可以正确地访问obj 对象的属性。 另一种解决方法是使用箭头函数。 由于箭头函数没有自己的this ,它会继承它所在作用域的this 。 因此,在箭头函数中,this 关键字引用的是定义该函数时所在的对象。 代码略

    原因六:forEach性能比for循环低

    for :for循环没有额外的函数调用栈和上下文,所以它的实现最为简单。 forEach :对于forEach来说,它的函数签名中包含了参数和上下文,所以性能会低于 for 循环。

    原因七:会跳过已删除或者未初始化的项

    // 跳过未初始化的值 const array = [1, 2, /* empty */, 4]; let num = 0; array.forEach((ele) => { console.log(ele); num++; }); console.log("num:",num); // 1 // 2 // 4 // num: 3 // 跳过已删除的值 const words = ['one', 'two', 'three', 'four']; words.forEach((word) => { console.log(word); if (word === 'two') { // 当到达包含值 `two` 的项时,整个数组的第一个项被移除了 // 这导致所有剩下的项上移一个位置。 因为元素 `four` 正位于在数组更前的位置,所以 `three` 会被跳过。 words.shift(); //'one' 将从数组中删除 } }); // one // two // four console.log(words); // ['two', 'three', 'four']

    原因八:forEach使用不会改变原数组

    forEach() 被调用时,不会改变原数组,也就是调用它的数组。 但是那个对象可能会被传入的回调函数改变 // 例子一 const array = [1, 2, 3, 4]; array.forEach(ele => { ele = ele * 3 }) console.log(array); // [1,2,3,4] // 解决方式,改变原数组 const numArr = [33,4,55]; numArr.forEach((ele, index, arr) => { if (ele === 33) { arr[index] = 999 } }) console.log(numArr); // [999, 4, 55] // 例子二 const changeItemArr = [{ name: 'wxw', age: 22 }, { name: 'wxw2', age: 33 }] changeItemArr.forEach(ele => { if (ele.name === 'wxw2') { ele = { name: 'change', age: 77 } } }) console.log(changeItemArr); // [{name: "wxw", age: 22},{name: "wxw2", age: 33}] // 解决方式 const allChangeArr = [{ name: 'wxw', age: 22}, { name: 'wxw2', age: 33}] allChangeArr.forEach((ele, index, arr) => { if (ele.name === 'wxw2') { arr[index] = { name: 'change', age: 77 } } }) console.log(allChangeArr); // // [{name: "wxw", age: 22},{name: "change", age: 77}] 还是使用for...of 去替代forEach 吧 fs.readFile('myjsonfile.json', 'utf8', function readFileCallback(err, data){ if (err){ console.log(err); } else { obj = JSON.parse(data); //now it an object obj.date.push({id: 2, square:3}); //add some data json = JSON.stringify(obj); //convert it back to json fs.writeFile('myjsonfile.json', json, 'utf8', callback); // write it back }}); This will work for data that is up to 100 MB effectively. Over this limit, you should use a database engine. UPDATE: Create a function which returns the current date (year+month+day) as a string. Create the file named this string + .json. the fs module has a function which can check for file existence named fs.stat(path, callback). With this, you can check if the file exists. If it exists, use the read function if it's not, use the create function. Use the date string as the path cuz the file will be named as the today date + .json. the callback will contain a stats object which will be null if the file does not exist. anothe simple method: var fs = require('fs'); var data = {} data.date = [] for (i=0; i <26 ; i++){ var obj = { id: i, square: i * i } data.date.push(obj) } fs.writeFile ("input.json", JSON.stringify(data), function(err) { if (err) throw err; console.log('complete'); } );

    promise examples



    Promise 接受一个函数作为参数,该函数是同步的并且会被立即执行,所以我们称之为起始函数。 起始函数包含两个参数 resolve 和 reject,分别表示 Promise 成功和失败的状态。

    example1: setTimeout

    const promise = new Promise( (resolve, reject) => { setTimeout( () => { if (Math.random() < 0.5) { resolve('success'); } else { reject('error'); } }, 1000 ); } ); promise.then( result => { console.log(result); } ).catch( error => { console.log(error); } );

    example2: some_module.some_function

    some_function = function(username, password) { return new Promise( function(resolve, reject) { if (/* everything turned out fine */) { resolve("Stuff worked!"); } else { reject(Error("It broke")); } } ); }; Then, use it: some_module.some_function(username, password).then(function(uid) { // stuff });

    example3: dayOfTheYear

    function dayOfTheYear() { return new Promise((resolve) => { const now = new Date(); const start = new Date(now.getFullYear(), 0, 0); const diff = now - start; const oneDay = 1000 * 60 * 60 * 24; const day = Math.floor(diff / oneDay); resolve(day); // this is you resolving the promise you return }); } //If we were to use the above function, //there would be two different ways to do it: dayOfTheYear() .then( (resolvedValue) => console.log(resolvedValue) ) //The resolvedValue is what was resolved in your function in the call to resolve(day). Or instead of using the then function to pass in a callback, you could instead use await: // assuming this code is in a function declared as async const resolvedValue = await dayOfTheYear(); So from the above, you can see that the return statement from an async function does the same thing as the resolve call from a Promise callback. const value = await (the promise) to assign a value to a variable await stops executing until the Promise has resolved (ie, has a value). Unlike using .then() you can just keep awaiting values as you run various functions that return promises, and execution continues onto the next line (this is called 'direct style). It's also much nicer to look at than .then() everywhere, since it's consistent with the rest of JavaScript.

    example4: async

    // Example function that returns a Promise that will resolve after 2 seconds var getGenres = function() { return new Promise( function(resolve) { setTimeout( function(){ resolve(['comedy', 'drama', 'action']) }, 2000 ); } ); } // We start an 'async' function to use the 'await' keyword (async function(){ var result = await getGenres() console.log('Woo done!', result) // But the best part is, we can just keep awaiting different stuff, without ugly .then()s var somethingElse = await getSomethingElse() var moreThings = await getMoreThings() })() The way I like to do it is to create a let variable and assign the 'then' result to that variable. Const won't work because it will give you an error. It will be like let value_result = function_that_returns_promise.then(result => value_result = result) For your example, I made the method into a function for simplicity: const genres = ['comedy', 'drama', 'action']; function getGenres() { var promise = new Promise( (resolve, reject) => { let result = genres[0] //just picking out the first one as example resolve(result) }) return promise } const result_as_promise = getGenres() console.log(result_as_promise); //output: //Promise { 'comedy' } let result_as_value = getGenres().then(result => result_as_value = result) setTimeout(function() { console.log(result_as_value); }, 0); //output: //comedy

    Promise 中文 explain

    Promise 构造函数接受一个函数作为参数,该函数是同步的并且会被立即执行,所以我们称之为起始函数。 起始函数包含两个参数 resolve 和 reject,分别表示 Promise 成功和失败的状态。 起始函数执行成功时,它应该调用 resolve 函数并传递成功的结果。 当起始函数执行失败时,它应该调用 reject 函数并传递失败的原因。 Promise 构造函数返回一个 Promise 对象,该对象具有以下几个方法: then:用于处理 Promise 成功状态的回调函数。 catch:用于处理 Promise 失败状态的回调函数。 finally:无论 Promise 是成功还是失败,都会执行的回调函数。

    example: 异步操作

    下面是一个使用 Promise 构造函数创建 Promise 对象的例子: 当 Promise 被构造时,起始函数会被同步执行: const promise = new Promise( (resolve, reject) => { // 异步操作 setTimeout( () => { if (Math.random() < 0.5) { resolve('success'); } else { reject('error'); } }, 1000); } ); 执行 promise: promise.then( result => { console.log(result); } ).catch( error => { console.log(error); } ); 实例 new Promise( function (resolve, reject) { var a = 0; var b = 1; if (b == 0) reject("Divide zero"); else resolve(a / b); } ).then( //成功状态 function (value) { console.log("a / b = " + value); }).catch( //失败状态 function (err) { console.log(err); }).finally( function () { console.log("End"); } );

    async function 异步函数

    实例 function print(delay, message) { return new Promise(function (resolve, reject) { setTimeout(function () { console.log(message); resolve(); }, delay); }); } 用不同的时间间隔输出了三行文本: 实例 print(1000, "First").then( function () { return print(4000, "Second"); } ).then( function () { print(3000, "Third"); } ); 我们可以将这段代码变得更好看: 实例 async function asyncFunc() { await print(1000, "First"); await print(4000, "Second"); await print(3000, "Third"); } asyncFunc(); 这将异步操作变得像同步操作一样容易了! 异步函数 async function 中可以使用 await 指令, await 指令后必须跟着一个 Promise, 异步函数会在这个 Promise 运行中暂停,直到其运行结束再继续运行。 异步函数实际上原理与 Promise 原生 API 的机制是一模一样的,只不过更便于程序员阅读。

    try-catch example

    处理异常的机制将用 try-catch 块实现: 实例 async function asyncFunc() { try { await new Promise(function (resolve, reject) { throw "Some error"; // 或者 reject("Some error") }); } catch (err) { console.log(err); // 会输出 Some error } } asyncFunc(); 如果 Promise 有一个正常的返回值,await 语句也会返回它: 实例 async function asyncFunc() { let value = await new Promise( function (resolve, reject) { resolve("Return value"); } ); console.log(value); } asyncFunc(); 程序会输出: Return value

    Promises with Loops and Array



    https://sliceofdev.com/posts/promises-with-loops-and-array-methods-in-javascript Promises are objects that represent the eventual completion (or failure) of an asynchronous operation and allow you to handle the result of that operation when it completes. Loops are used to execute a block of code multiple times. However, when working with asynchronous code, it’s important to understand how loops behave and how to use promises to control the flow of execution.

    Usage with for..of loop

    One common use case for using promises with loops is when you need to perform an operation multiple times, but each operation depends on the result of the previous one. In this case, you can use a loop to iterate over the data and a promise to control the flow of execution. Let’s take a look at an example: const items = [1, 2, 3, 4, 5]; function processItem(item) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(`Processing item ${item}`); resolve(item); }, Math.random() * 1000); }); } async function processItems() { let result = 0 for (const item of items) { result = await processItem(result + item); } console.log('All items processed'); } processItems(); Executing this code will work sequentially as expected adding the result of the previous item to the current item. But, if waiting for the previous result is not required or the order of execution doesn’t matter, it is best not to wait for the results and remove the keywords async and await . This way, the code can execute concurrently without blocking the main thread. function processItems() { for (const item of items) { processItem(item); } } processItems(); console.log('All items sent for processing'); Sometimes it is required to wait for all the concurrent tasks before returning from the function or exiting the code. Promise.all can be used in this case to wait for the result. async function processItems() { const promiseArray = [] for (const item of items) { promiseArray.push(processItem(item)); } const result = await Promise.all(promiseArray); console.log(result); } processItems(); console.log('All items sent for processing'); Usage of Promises with traditional for(let i=0;i<10;i++) loops will also behave like the above examples.

    Usage with Array Methods

    Often there are times when an asynchronous operation needs to be carried out for each item of an array. Let’s take a look at the different ways of doing that.

    Using forEach

    We can use the forEach() method to iterate over the array, and use Promises to execute the asynchronous operation for each object concurrently. Here's how it might look: async function processItems() { items.forEach((item) => { processItem(item); }) } processItems(); As forEach takes a function as an argument, each item is processed separately in the function. So even if the async and await keywords are added to the function, forEach will still run the asynchronous code concurrently. // still runs concurrently async function processItems() { items.forEach(async (item) => { await processItem(item); }) } It’s recommended to use for..of loop if it is required to wait for each promise to complete or to run the asynchronous operations sequentially for each item. The promises can be executed sequentially by chaining the promises but it's generally not a good practice. See the following example for the promise chain trick. function processItems() { let chainedPromise = Promise.resolve(); items.forEach((item) => { chainedPromise = chainedPromise.then(() => { return processItem(item); }) }); } processItems();

    Using map

    map method behaves very similarly to forEach with the difference being it allows to return a value for each item of an array. Let’s rewrite the above examples with map . function processItems() { items.map((item) => { processItem(item); }) } processItems(); The above example runs concurrently. map makes it easier for using Promise.all as it allows us to return a value so that we can wait for the results of the promises. Let’s return the promise from the map function and use it in a Promise.all async function processItems() { const promiseArray = items.map((item) => { return processItem(item); }) const result = await Promise.all(promiseArray); console.log(result); } processItems(); The code still runs concurrently and then awaited for all the Promises to settle. The promise chain trick we saw previously can be used with map if the Promises need to be executed sequentially. async function processItems() { let chainedPromise = Promise.resolve(); const promiseArray = items.map((item) => { return chainedPromise = chainedPromise.then(() => { return processItem(item) }); }) const result = await Promise.all(promiseArray); console.log(result); } processItems();

    Error Handling

    When working with Promises, there’s always the possibility of an error occurring. It’s important to handle these errors to prevent the program from crashing or behaving unexpectedly. The following error is generally thrown when a Promise rejection error is not handled properly. UnhandledPromiseRejectionWarning: Unhandled promise rejection ...

    Handling with the .catch method

    The errors should be handled with the .catch method on a Promise object. Otherwise, the process will be terminated with a non-zero exit code. The examples above for .forEach and .map can be modified to handle the errors with the .catch method. function processItem(item) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(`Processing item ${item}`); Math.random() > 0.5 ? resolve(item) : reject(`error occurred for ${item}`); }, Math.random() * 1000); }); } function processItems() { items.forEach((item) => { processItem(item).catch(err => { console.log(err); }) }) } This will gracefully handle the errors and log them to the console. Otherwise, it would have crashed the program.

    Handling errors in Promise.all

    If any promise is rejected from the promise array passed to Promise.all , Promise.all will also reject and throw an error. To fix this, again, every promise should end with a .catch method. async function processItems() { const promiseArray = items.map((item) => { return processItem(item) .catch(err => console.log(err)); }) const result = await Promise.all(promiseArray); console.log(result); } Promise.allSettled can also be used as an alternative, it will always resolve even if any or all of the promises throw an error. async function processItems() { const promiseArray = items.map((item) => { return processItem(item); }) const result = await Promise.allSettled(promiseArray); console.log(result); } [ { status: 'rejected', reason: 'error occurred for 1' }, { status: 'fulfilled', value: 2 }, { status: 'fulfilled', value: 3 }, { status: 'fulfilled', value: 4 }, { status: 'rejected', reason: 'error occurred for 5' } ]

    Handling errors using try/catch block

    An alternative to .catch method is using traditional try {...} catch() {...} blocks. But this should only be used if the promise is awaited using the await keyword. try/catch will have no effect if the promise is not awaited. function processItems() { items.forEach(async (item) => { try { await processItem(item); } catch(err) { console.log(err); } }) } Note that the following code would still throw an error because try/catch block only handles promises awaited with the await keyword. function processItems() { items.forEach((item) => { try { processItem(item); // error } catch(err) { console.log(err); } }) }

    Promise高级技巧

    JavaScript项目中 Promise 的使用是必不可少的。 许多开发人员仍然停留在常见的 promiseInst.then()、 promiseInst.catch()、 Promise.all 甚至 async/await等常规实践上,没有深入理解。 Promise 有许多巧妙的高级用法,一些在ALOVA请求策略库中广泛使用。 ALOVA 是一个基于 Promise 的请求策略库,旨在帮助开发者更高效地进行 HTTP 请求处理。 它通过 Promise 技巧,实现了请求共享、缓存、批量请求等功能,从而简化了前端开发中的数据请求管理。

    串行执行Promise数组

    例如,如果你有一组需要串行执行的接口,首先你可能会想到使用 await。 const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()]; for (const requestItem of requestAry) { await requestItem(); } 如果使用Promise语法,你可以使用then函数将多个Promise串起来,从而实现顺序执行。 const requestAry = [() => api.request1(), () => api.request2(), () => api.request3()]; const finallyPromise = requestAry.reduce( (currentPromise, nextRequest) => currentPromise.then(() => nextRequest()), Promise.resolve() // 创建一个初始Promise以串联数组中的Promise。 );

    在新Promise作用域外改变状态

    假设你有一些页面上的函数需要在使用前收集用户信息,一种方法是在点击某个功能前弹出信息收集对话框。 写在一个所有页面都能调用的地方更好 让我们看看高级前端是如何实现的。 以Vue3为例,看下面的示例。 <!-- App.vue --> <template> <!-- 以下是模态组件。 --> <div class="modal" v-show="visible"> <div> 用户名:<input v-model="info.name" /> </div> <!-- 其他信息 --> <button @click="handleCancel">取消</button> <button @click="handleConfirm">提交</button> </div> <!-- 页面组件 --> </template> <script setup> import { provide } from 'vue'; const visible = ref(false); const info = reactive({ name: '' }); let resolveFn, rejectFn; // 将信息收集函数传递给以下内容。 provide('getInfoByModal', () => { visible.value = true; return new Promise((resolve, reject) => { // 将两个函数赋值给外部,突破Promise作用域。 resolveFn = resolve; rejectFn = reject; }); }); const handleConfirm = () => { resolveFn && resolveFn(info); }; const handleCancel = () => { rejectFn && rejectFn(new Error('用户已取消。 ')); }; </script> 接下来,直接调用 getInfoByModal 即可使用模态框,并轻松获取用户填写的数据。 <template> <button @click="handleClick">填写信息</button> </template> <script setup> import { inject } from 'vue'; const getInfoByModal = inject('getInfoByModal'); const handleClick = async () => { // 调用后,会显示模态框。 当用户点击“确认”时,Promise会变为fulfilled状态,从而获取用户信息。 const info = await getInfoByModal(); await api.submitInfo(info); } </script> 这也是许多UI组件库中封装常用组件的方法。

    async/await的替代用法

    许多人只知道在调用 async function 时使用 await 接收返回值,但他们不知道async函数实际上是返回Promise的函数。 例如,以下两个函数是等价的: const fn1 = async () => 1; const fn2 = () => Promise.resolve(1); fn1(); // 同样返回一个值为1的Promise对象。 在大多数情况下,await 后面跟着的是一个Promise对象,并等待其变为 fulfilled 状态。 因此,下面的函数 fn1 等待也是等价的: await fn1(); const promiseInst = fn1(); await promiseInst; 然而,await 有一个不为人知的秘密。 当它后面跟的是非Promise对象的值时,它会使用 Promise 对象包装该值。 因此,await 后的代码总是异步执行的。 例如: Promise.resolve().then(() => { console.log(1); }); await 2; console.log(2); // 输出顺序:1 2 等价于 Promise.resolve().then(() => { console.log(1); }); Promise.resolve().then(() => { console.log(2); });

    使用Promise实现请求共享

    当一个请求已经发送但尚未响应时,再次发出相同请求会导致浪费请求。 此时,我们可以与第二个请求共享第一个请求的响应。 request('GET', '/test-api').then(response1 => { // ... }); request('GET', '/test-api').then(response2 => { // ... }); 以上两个请求只会发送一次,并同时接收相同的响应值。 那么,请求共享有哪些场景呢? 我认为有三种: 当一个页面同时渲染多个内部组件获取数据时; 提交按钮未禁用,用户连续多次点击提交按钮; 在预加载数据的情况下,进入预加载页面前完成预加载; 这也是Alova的高级功能之一。 实现请求共享需要使用 Promise 缓存功能。 也就是说,一个Promise对象可以通过多次await调用获取数据。 简单的实现思路如下: const pendingPromises = {}; function request(type, url, data) { // 使用请求信息作为唯一请求键来缓存正在请求的Promise对象。 // 具有相同键的请求将重用该Promise。 const requestKey = JSON.stringify([type, url, data]); if (pendingPromises[requestKey]) { return pendingPromises[requestKey]; } const fetchPromise = fetch(url, { method: type, data: JSON.stringify(data) }) .then(response => response.json()) .finally(() => { delete pendingPromises[requestKey]; }); return pendingPromises[requestKey] = fetchPromise; }

    如果同时调用resolve和reject会发生什么

    大家都知道,Promise有三种状态:pending、fulfilled 和 rejected。 但在下面的例子中,Promise 的最终状态是什么? const promise = new Promise((resolve, reject) => { resolve(); reject(); }); 正确答案是 fulfilled 状态。 我们只需记住,一旦Promise从pending状态转变为其他状态,就不能再改变。 因此,在这个例子中,调用 resolve()后,即使调用 reject(),状态也不会再改变。

    彻底弄清then/catch/finally的返回值

    总结一句话,上述三个函数都会返回一个新的 Promise包装对象,包装的值是执行回调函数的返回值。 如果回调函数抛出错误,它将包装一个处于 rejected 状态的 Promise。 这不太容易理解,我们来看一个例子: 你可以将它们一个一个复制并在浏览器控制台中运行,以更好地理解。 // then函数 Promise.resolve().then(() => 1); // return new Promise(resolve => resolve(1)) Promise.resolve().then(() => Promise.resolve(2)); // return new Promise(resolve => resolve(Promise.resolve(2))) Promise.resolve().then(() => { throw new Error('abc') }); // return new Promise(resolve => resolve(Promise.reject(new Error('abc')))) Promise.reject().then(() => 1, () => 2); // return new Promise(resolve => resolve(2)) // catch函数 Promise.reject().catch(() => 3); // return new Promise(resolve => resolve(3)) Promise.resolve().catch(() => 4); // 返回值是一个新的Promise,解析为调用catch的Promise对象。 // 当finally函数的返回值不是Promise时,返回finally函数之前的Promise对象。 Promise.resolve().finally(() => {}); // return Promise.resolve() Promise.reject().finally(() => {}); // return Promise.reject() // 当finally函数的返回值是Promise时,等待返回的Promise解析后再返回finally函数之前的Promise对象。 Promise.resolve(5).finally(() => new Promise(res => { setTimeout(res, 1000); })); // 返回一个处于pending状态的Promise,1秒后解析为5。 Promise.reject(6).finally(() => new Promise(res => { setTimeout(res, 1000); })); // 返回一个处于pending状态的Promise,1秒后抛出数字6。

    then函数的第二个回调与catch回调有何不同

    Promise中的 then 函数的第二个回调和 catch 函数在请求失败时都会被触发。 乍一看,它们似乎没有太大区别,但实际上,前者无法捕捉当前 then 函数第一个回调函数中抛出的错误,而 catch 函数可以。 Promise.resolve().then( () => { throw new Error('成功回调中的错误'); }, () => { // 不会执行 } ).catch(reason => { console.log(reason.message); // 打印“成功回调中的错误” }); 其原理如前所述,catch 函数是在 then 函数返回的 Promise 处于 rejected 状态时调用的,自然可以捕捉到其错误。

    实现Koa2洋葱模型中的Promise

    Koa2框架引入了洋葱模型,使你的请求像剥洋葱一样逐层处理,按相反顺序进入和退出层,从而实现请求的统一前后处理。 我们看看一个简单的Koa2洋葱模型: const app = new Koa(); app.use(async (ctx, next) => { console.log('a-start'); await next(); console.log('a-end'); }); app.use(async (ctx, next) => { console.log('b-start'); await next(); console.log('b-end'); }); app.listen(3000); 上面的输出是 a-start -> b-start -> b-end -> a-end。 这种神奇的输出顺序是如何实现的呢? 我用了大约20行代码实现了这个简单的实现,巧合的是,它与Koa相似。 接下来,让我们进一步分析。 保存中间件函数,然后在 listen 函数中接收到请求时调用洋葱模型的执行。 function action(koaInstance, ctx) { // ... } class Koa { middlewares = []; use(mid) { this.middlewares.push(mid); } listen(port) { // 模拟接收请求的伪代码 http.on('request', ctx => { action(this, ctx); }); } } 接收到请求后,从第一个中间件开始按顺序执行前置逻辑,调用 next。 // 开始中间件调用。 function action(koaInstance, ctx) { let nextMiddlewareIndex = 1; // 标识下一个执行的中间件索引 // 定义next函数。 function next() { // 在剥洋葱之前,调用next会调用下一个中间件函数。 const nextMiddleware = middlewares[nextMiddlewareIndex]; if (nextMiddleware) { nextMiddlewareIndex++; nextMiddleware(ctx, next); } } // 从第一个中间件函数开始执行,并传入ctx和next函数。 middlewares[0](ctx, next); } 处理“next”之后的后置逻辑 function action(koaInstance, ctx) { let nextMiddlewareIndex = 1; function next() { const nextMiddleware = middlewares[nextMiddlewareIndex]; if (nextMiddleware) { nextMiddlewareIndex++; // 这里还添加了一个return,使中间件函数的执行通过Promise从后向前连接(建议反复理解这个return)。 return Promise.resolve(nextMiddleware(ctx, next)); } else { // 在最后一个中间件的前置逻辑执行完后,返回的fulfilled Promise将开始执行next之后的后置逻辑。 return Promise.resolve(); } } middlewares[0](ctx, next); }

    Learn Promises


    Promises (like callbacks) allow us to wait on certain code to finish execution prior to running the next bit of code. Our Promise can have one of three states: Pending — Asynchronous operation has not completed yet Fulfilled — Operation has completed and the Promise has a value Rejected — Operation has completed with an error or failed. A promise is settled if it is not pending. Once a Promise has settled, it is settled for good. It cannot transition to any other state.

    Working With Promises

    Most of the time when working with Promises, you will be consuming already-created promises that have been returned from functions. However, you can also create a promise with it’s constructor. Here’s what a simple Promise might look like: runFunction().then(successFunc, failureFunc); In the above example, we first invoke the runFunction() function. Since runFunction() returns a promise, only when the Promise is settled can our successFunc, or failureFunc function run. If the Promise is Fulfilled, our sucessFunc is invoked. If the Promise fails, our failureFunc is invoked.

    A Promise Example

    It’s okay if this doesn’t make sense yet: function delay(t){ return new Promise(function(resolve){ return setTimeout(resolve, t) }); } function logHi(){ console.log('hi'); } delay(2000).then(logHi); Above we have two functions — a delay() function and a logHi() function. The logHi() function simply logs 'hi' to the console. The delay() function is a little more complicated. It returns a Promise that will resolve after a supplied time frame. We use the then() method to register callbacks to receive either the eventual fulfilled or rejected value. With this in mind, we can use delay(2000).then(logHi) to pass in 2000 milliseconds (2 seconds) into our delay function. After 2 seconds have passed, our Promise will resolve, and only then will our logHi function be invoked. You can try this out yourself by opening up the Google Chrome Developer Tools and typing the above code into your console!

    Chaining Promises

    One of the main benefits of Promises is that they allow us to chain asynchronous operations together. This means we can specify subsequent operations to start only when the previous operation has succeeded. This is called a Promise Chain. Here’s an example: new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 2000); }).then((result) => { alert(result); return result + 2; }).then((result) => { alert(result); return result + 2; }).then((result) => { alert(result); return result + 2; }); Above, our initial promise is going to resolve in 2000 milliseconds with a value of 1. After resolving, the then() handler is called and the value of 1 is alerted to the screen. Finally, the value is added to 2, and our new value of 3 is returned. This value is passed on to the next then() handler, and the process repeats. Obviously this is not a real world example, but it should illustrate for you how Promises can be chained together. This is very useful with certain tasks in JavaScript such as loading external resources, or for waiting for API data before processing it.

    Error Handling

    Up until this point, we’ve only dealt with resolved promises. That’s about to change. We can use .catch() to catch all of our errors in our Promise chain. Lets look at what a .catch() might look like: // .... }) .catch((e) => { console.log('error: ', e) } Above I’ve created a simple .catch() that will take the returned error message and log it to the console. Lets add in error handling to the previous example now. Below, there are only two changes. After the second .then() I’ve added in an error and an error message. I’ve also added our .catch() to the end of the chain. What do you expect to happen when this code is run: new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 2000); }).then((result) => { alert(result); return result + 2; }).then((result) => { throw new Error('FAILED HERE'); alert(result); return result + 2; }).then((result) => { alert(result); return result + 2;}).catch((e) => { console.log('error: ', e) }); Here’s what happens: Our Promise resolves after 2 seconds with a value of 1 This value is passed to the first .then() and alerted to the screen. 2 is added and a new value of 3 is passed to the second .then() A new Error is thrown. Execution stops immediately and the Promise resolves to a rejected state. .catch() receives our error value and logs it to the screen.

    then()



    The then() method in JavaScript is used with promises to handle asynchronous operations. It accepts two callback functions: one for handling a promise’s resolved value and one for handling its rejection. It returns a new promise, allowing for method chaining.

    Why we use then() method

    -Handle Results: then() processes promise outcomes, allowing actions based on successful resolution or errors. -Callback Functions: Provides callbacks for success and failure, ensuring proper handling of asynchronous tasks. -Method Chaining: Enables chaining multiple then() calls for sequential asynchronous operations, simplifying code readability and flow.

    Syntax

    demo().then( (onResolved) => { // Some task on success }, (onRejected) => { // Some task on failure } ) Note: demo is a function that returns a promise prototype. Parameters: onFulfilled: This is a function that is called upon to the success of the promise. This is an optional parameter. onRejected: This is a function that is called upon the rejection of the promise. This is an optional parameter. Return Value: This method can either return a Promise (if further another then() is called) or nothing.

    Example 1:

    In this example, we have not passed any arguments. function demo() { console.log("Function called!!<br>") return Promise.resolve("Success"); // or // return Promise.reject("Failure"); } demo().then() Function called!!

    Example 2:

    In this example, we are Passing only the first callback. function demo() { console.log("Function called!!") return Promise.resolve("Success"); // or // return Promise.reject("Failure"); } demo().then( (message) => { console.log("Then success:" + message); } ) Function called!! Then success:Success Note: If the demo function returns a reject then it will generate an error.

    Example 3:

    In this example, we are Passing both the arguments. function demo() { console.log("Function called!!") return Promise.resolve("Success"); // or // return Promise.reject("Failure"); } demo().then( (message) => { console.log("Then success:" + message); }, (message) => { console.log("Then failure:" + message); } ) Function called!! Then success:Success

    Example 4:

    In this example, we are using Chaining Multiple then() methods. Each then() can return a promise (a resolve or a reject) and therefore multiple then() methods can be chained together. function demo() { console.log("Function called!!") return Promise.resolve(1); // or // return Promise.reject("Failure"); } demo().then( (value) => { console.log(value); return ++value; }, (message) => { console.log(message); } ).then( (value) => { console.log(value); }, (message) => { console.log(message); } ) Function called!!

    Example 5:

    In this example, we are using then() as an asynchronous function. let demo = new Promise((resolve, reject) => { resolve(1); }) let call = demo.then( (value) => { console.log(value); return ++value; }, (message) => { console.log(message); }); console.log(call); setTimeout(() => { console.log(call); }); Promise {status: "pending"} 1 Promise {status: "resolved", result: 2}

    async/await



    async function

    让我们以 async 这个关键字开始。 它可以被放置在一个函数前面,如下所示: async function f() { return 1; } 在函数前面的 “async” 这个单词表达了一个简单的事情:即这个函数总是返回一个 promise。 其他值将自动被包装在一个 resolved 的 promise 中。 例如,下面这个函数返回一个结果为 1 的 resolved promise,让我们测试一下: async function f() { return 1; // note that the return value will be set to a promise! } f().then(alert); // 1, since the returned value is a promise, so we can use the .then() function ……我们也可以显式地返回一个 promise,结果是一样的: async function f() { return Promise.resolve(1); } f().then(alert); // 1 所以说,async 确保了函数返回一个 promise,也会将非 promise 的值包装进去。 还有另外一个叫 await 的关键词,它只在 async 函数内工作。

    await

    语法如下: // 只在 async 函数内工作 let value = await promise; 关键字 await 让 JavaScript 引擎等待直到 promise 完成(settle)并返回结果。 这里的例子就是一个 1 秒后 resolve 的 promise: async function f() { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve("done!"), 1000) }); let result = await promise; // 等待,直到 promise resolve (*) alert(result); // "done!" } f(); 这个函数在执行的时候,“暂停”在了 (*) 那一行,并在 promise settle 时,拿到 result 作为结果继续往下执行。 所以上面这段代码在一秒后显示 “done!”。 让我们强调一下:await 实际上会暂停函数的执行,直到 promise 状态变为 settled,然后以 promise 的结果继续执行。 这个行为不会耗费任何 CPU 资源,因为 JavaScript 引擎可以同时处理其他任务:执行其他脚本,处理事件等。 相比于 promise.then,它只是获取 promise 的结果的一个更优雅的语法。 并且也更易于读写。 !!! 不能在普通函数中使用 await 如果我们尝试在非 async 函数中使用 await,则会报语法错误: function f() { let promise = Promise.resolve(1); let result = await promise; // Syntax error } 如果我们忘记在函数前面写 async 关键字,我们可能会得到一个这个错误。 就像前面说的,await 只在 async 函数中有效。 让我们拿 Promise 链 那一章的 showAvatar() 例子,并将其改写成 async/await 的形式: 我们需要用 await 替换掉 .then 的调用。 另外,我们需要在函数前面加上 async 关键字,以使它们能工作。 async function showAvatar() { // 读取我们的 JSON let response = await fetch('/article/promise-chaining/user.json'); let user = await response.json(); // 读取 github 用户信息 let githubResponse = await fetch(`https://api.github.com/users/${user.name}`); let githubUser = await githubResponse.json(); // 显示头像 let img = document.createElement('img'); img.src = githubUser.avatar_url; img.className = "promise-avatar-example"; document.body.append(img); // 等待 3 秒 await new Promise((resolve, reject) => setTimeout(resolve, 3000)); img.remove(); return githubUser; } showAvatar(); !!! 现代浏览器在 modules 里允许顶层的 await 在现代浏览器中,当我们处于一个 module 中时,那么在顶层使用 await 也是被允许的。 我们将在 模块 (Module) 简介 中详细学习 modules。 例如: // 我们假设此代码在 module 中的顶层运行 let response = await fetch('/article/promise-chaining/user.json'); let user = await response.json(); console.log(user); 如果我们没有使用 modules,或者必须兼容 旧版本浏览器 ,那么这儿还有一个通用的方法:包装到匿名的异步函数中。 像这样: (async () => { let response = await fetch('/article/promise-chaining/user.json'); let user = await response.json(); ... })(); !!! await 接受 “thenables” 像 promise.then 那样,await 允许我们使用 thenable 对象(那些具有可调用的 then 方法的对象)。 这里的想法是,第三方对象可能不是一个 promise,但却是 promise 兼容的:如果这些对象支持 .then,那么就可以对它们使用 await。 这有一个用于演示的 Thenable 类,下面的 await 接受了该类的实例: class Thenable { constructor(num) { this.num = num; } then(resolve, reject) { alert(resolve); // 1000ms 后使用 this.num*2 进行 resolve setTimeout(() => resolve(this.num * 2), 1000); // (*) } } async function f() { // 等待 1 秒,之后 result 变为 2 let result = await new Thenable(1); alert(result); } f(); 如果 await 接收了一个非 promise 的但是提供了 .then 方法的对象,它就会调用这个 .then 方法,并将内建的函数 resolve 和 reject 作为参数传入(就像它对待一个常规的 Promise executor 时一样)。 然后 await 等待直到这两个函数中的某个被调用(在上面这个例子中发生在 (*) 行),然后使用得到的结果继续执行后续任务。 !!! Class 中的 async 方法 要声明一个 class 中的 async 方法,只需在对应方法前面加上 async 即可: class Waiter { async wait() { return await Promise.resolve(1); } } new Waiter() .wait() .then(alert); // 1(alert 等同于 result => alert(result)) 这里的含义是一样的:它确保了方法的返回值是一个 promise 并且可以在方法中使用 await。

    Error 处理

    如果一个 promise 正常 resolve,await promise 返回的就是其结果。 但是如果 promise 被 reject,它将 throw 这个 error,就像在这一行有一个 throw 语句那样。 这个代码: async function f() { await Promise.reject(new Error("Whoops!")); } ……和下面是一样的: async function f() { throw new Error("Whoops!"); } 在真实开发中,promise 可能需要一点时间后才 reject。 在这种情况下,在 await 抛出(throw)一个 error 之前会有一个延时。 我们可以用 try..catch 来捕获上面提到的那个 error,与常规的 throw 使用的是一样的方式: async function f() { try { let response = await fetch('http://no-such-url'); } catch(err) { alert(err); // TypeError: failed to fetch } } f(); 如果有 error 发生,执行控制权马上就会被移交至 catch 块。 我们也可以用 try 包装多行 await 代码: async function f() { try { let response = await fetch('/no-user-here'); let user = await response.json(); } catch(err) { // 捕获到 fetch 和 response.json 中的错误 alert(err); } } f(); 如果我们没有 try..catch,那么由异步函数 f() 的调用生成的 promise 将变为 rejected。 我们可以在函数调用后面添加 .catch 来处理这个 error: async function f() { let response = await fetch('http://no-such-url'); } // f() 变成了一个 rejected 的 promise f().catch(alert); // TypeError: failed to fetch // (*) 如果我们忘了在这添加 .catch,那么我们就会得到一个未处理的 promise error(可以在控制台中查看)。 我们可以使用在 使用 promise 进行错误处理 一章中所讲的全局事件处理程序 unhandledrejection 来捕获这类 error。 !!! async/await 和 promise.then/catch 当我们使用 async/await 时,几乎就不会用到 .then 了,因为 await 为我们处理了等待。 并且我们使用常规的 try..catch 而不是 .catch。 这通常(但不总是)更加方便。 但是当我们在代码的顶层时,也就是在所有 async 函数之外,我们在语法上就不能使用 await 了,所以这时候通常的做法是添加 .then/catch 来处理最终的结果(result)或掉出来的(falling-through)error,例如像上面那个例子中的 (*) 行那样。 !!! async/await 可以和 Promise.all 一起使用 当我们需要同时等待多个 promise 时,我们可以用 Promise.all 把它们包装起来,然后使用 await: // 等待结果数组 let results = await Promise.all([ fetch(url1), fetch(url2), ... ]); 如果出现 error,也会正常传递,从失败了的 promise 传到 Promise.all,然后变成我们能通过使用 try..catch 在调用周围捕获到的异常(exception)。

    总结

    函数前面的关键字 async 有两个作用: 让这个函数总是返回一个 promise。 允许在该函数内使用 await。 Promise 前的关键字 await 使 JavaScript 引擎等待该 promise settle, 然后: 如果有 error,就会抛出异常 —— 就像那里调用了 throw error 一样。 否则,就返回结果。 这两个关键字一起提供了一个很好的用来编写异步代码的框架,这种代码易于阅读也易于编写。 有了 async/await 之后,我们就几乎不需要使用 promise.then/catch,但是不要忘了它们是基于 promise 的,因为有些时候(例如在最外层作用域)我们不得不使用这些方法。 并且,当我们需要同时等待需要任务时,Promise.all 是很好用的。

    用 async/await 来重写

    重写下面这个来自 Promise 链 一章的示例代码,使用 async/await 而不是 .then/catch: function loadJson(url) { return fetch(url) .then(response => { if (response.status == 200) { return response.json(); } else { throw new Error(response.status); } }); } loadJson('https://javascript.info/no-such-user.json') .catch(alert); // Error: 404 解决方案解析在代码下面: async function loadJson(url) { // (1) let response = await fetch(url); // (2) if (response.status == 200) { let json = await response.json(); // (3) return json; } throw new Error(response.status); } loadJson('https://javascript.info/no-such-user.json') .catch(alert); // Error: 404 (4) 解析: 将函数 loadJson 变为 async。 将函数中所有的 .then 都替换为 await。 我们可以返回 return response.json() 而不用等待它,像这样: if (response.status == 200) { return response.json(); // (3) } 然后外部的代码就必须 await 这个 promise resolve。 在本例中它无关紧要。 loadJson 抛出的 error 被 .catch 处理了。 在这儿我们我们不能使用 await loadJson(…),因为我们不是在一个 async 函数中。

    使用 async/await 重写 "rethrow"

    下面你可以看到 “rethrow” 的例子。 让我们来用 async/await 重写它,而不是使用 .then/catch。 同时,我们可以在 demoGithubUser 中使用循环以摆脱递归:在 async/await 的帮助下很容易实现。 class HttpError extends Error { constructor(response) { super(`${response.status} for ${response.url}`); this.name = 'HttpError'; this.response = response; } } function loadJson(url) { return fetch(url) .then(response => { if (response.status == 200) { return response.json(); } else { throw new HttpError(response); } }); } // 询问用户名,直到 github 返回一个合法的用户 function demoGithubUser() { let name = prompt("Enter a name?", "iliakan"); return loadJson(`https://api.github.com/users/${name}`) .then(user => { alert(`Full name: ${user.name}.`); return user; }) .catch(err => { if (err instanceof HttpError && err.response.status == 404) { alert("No such user, please reenter."); return demoGithubUser(); } else { throw err; } }); } demoGithubUser(); 这里没有什么技巧。 只需要将 demoGithubUser 中的 .catch 替换为 try...catch,然后在需要的地方加上 async/await 即可: class HttpError extends Error { constructor(response) { super(`${response.status} for ${response.url}`); this.name = 'HttpError'; this.response = response; } } async function loadJson(url) { let response = await fetch(url); if (response.status == 200) { return response.json(); } else { throw new HttpError(response); } } // 询问用户名,直到 github 返回一个合法的用户 async function demoGithubUser() { let user; while(true) { let name = prompt("Enter a name?", "iliakan"); try { user = await loadJson(`https://api.github.com/users/${name}`); break; // 没有 error,退出循环 } catch(err) { if (err instanceof HttpError && err.response.status == 404) { // 循环将在 alert 后继续 alert("No such user, please reenter."); } else { // 未知的 error,再次抛出(rethrow) throw err; } } } alert(`Full name: ${user.name}.`); return user; } demoGithubUser();

    在非 async 函数中调用 async 函数

    我们有一个名为 f 的“普通”函数。 你会怎样调用 async 函数 wait() 并在 f 中使用其结果? async function wait() { await new Promise(resolve => setTimeout(resolve, 1000)); return 10; } function f() { // ……这里你应该怎么写? // 我们需要调用 async wait() 并等待以拿到结果 10 // 记住,我们不能使用 "await" } P.S. 这个任务其实很简单,但是对于 async/await 新手开发者来说,这个问题却很常见。

    Async, Await

    Async,Await by Example
    javascript-async-await
    async-await
    proimse
    Understanding promises in JavaScript
    javascript-promises
    JavaScript Promises for Dummies
    promise-basics
    Tips For Using Async/Await in JavaScript
    JavaScript Async
    
    A “producing code” that does something and takes time.
    For instance, the code loads a remote script.
    A “consuming code” that wants the result of the “producing code” once it’s ready.
    A promise is a special JavaScript object that links the “producing code” and the “consuming code” together.
    
    JavaScript Async "async and await make promises easier to write" async makes a function return a Promise await makes a function wait for a Promise async function myFunction() { return "Hello"; } myFunction().then( function(value) {myDisplayer(value);} ); Await Syntax The keyword await before a function makes the function wait for a promise: let value = await promise; The await keyword can only be used inside an async function. Example async function myDisplay() { let myPromise = new Promise( function(myResolve, myReject) { myResolve("I love You !!"); } ); document.getElementById("demo").innerHTML = await myPromise; } myDisplay(); Waiting for a Timeout async function myDisplay() { let myPromise = new Promise( function(myResolve, myReject) { setTimeout( function() { myResolve("I love You !!"); }, 3000); } ); document.getElementById("demo").innerHTML = await myPromise; } myDisplay(); Waiting for a File async function getFile() { let myPromise = new Promise( function(myResolve, myReject) { let req = new XML req.open('GET', "mycar.html"); req.onload = function() { if (req.status == 200) {myResolve(req.response);} else {myResolve("File not Found");} }; req.send(); } ); document.getElementById("demo").innerHTML = await myPromise; } getFile(); Async/await Async/await Async functions Let’s start with the async keyword. It can be placed before a function, like this: async function f() { return 1; } The word “async” before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically. For instance, this function returns a resolved promise with the result of 1; let’s test it: async function f() { return 1; } f().then(alert); // 1 …We could explicitly return a promise, which would be the same: async function f() { return Promise.resolve(1); } f().then(alert); // 1 So, async ensures that the function returns a promise, and wraps non-promises in it. There’s another keyword, await, that works only inside async functions. Await // works only inside async functions let value = await promise; The keyword await makes JavaScript wait until that promise settles and returns its result. Here’s an example with a promise that resolves in 1 second: async function f() { let promise = new Promise( (resolve, reject) => { setTimeout( () => resolve("done!"), 1000 ) }); let result = await promise; // wait until the promise resolves (*) alert(result); // "done!" } f(); The function execution “pauses” at the line (*) and resumes when the promise settles, with result becoming its result. So the code above shows “done!” in one second. Let’s emphasize: await literally suspends the function execution until the promise settles, and then resumes it with the promise result. That doesn’t cost any CPU resources, because the JavaScript engine can do other jobs in the meantime: execute other scripts, handle events, etc. It’s just a more elegant syntax of getting the promise result than promise.then. And, it’s easier to read and write. Can’t use await in regular functions If we try to use await in a non-async function, there would be a syntax error: function f() { let promise = Promise.resolve(1); let result = await promise; // Syntax error } We may get this error if we forget to put async before a function. As stated earlier, await only works inside an async function. Let’s take the showAvatar() example from the chapter Promises chaining and rewrite it using async/await: We’ll need to replace .then calls with await. Also we should make the function async for them to work. async function showAvatar() { // read our JSON let response = await fetch('/article/promise-chaining/user.json'); let user = await response.json(); // read github user let githubResponse = await fetch(` let githubUser = await githubResponse.json(); // show the avatar let img = document.createElement('img'); img.src = githubUser.avatar_url; img.className = "promise-avatar-example"; document.body.append(img); // wait 3 seconds await new Promise((resolve, reject) => setTimeout(resolve, 3000)); img.remove(); return githubUser; } showAvatar(); Pretty clean and easy to read, right? Much better than before. await won’t work in the top-level code People who are just starting to use await tend to forget the fact that we can’t use await in top-level code. For example, this will not work: // syntax error in top-level code let response = await fetch('/article/promise-chaining/user.json'); let user = await response.json(); But we can wrap it into an anonymous async function, like this: (async () => { let response = await fetch('/article/promise-chaining/user.json'); let user = await response.json(); ... })(); P.S. New feature: starting from V8 engine version 8.9+, top-level await works in modules. await accepts “thenables” Like promise.then, await allows us to use thenable objects (those with a callable then method). The idea is that a third-party object may not be a promise, but promise-compatible: if it supports .then, that’s enough to use it with await. Here’s a demo Thenable class; the await below accepts its instances: class Thenable { constructor(num) { this.num = num; } then(resolve, reject) { alert(resolve); // resolve with this.num*2 after 1000ms setTimeout(() => resolve(this.num * 2), 1000); // (*) } } async function f() { // waits for 1 second, then result becomes 2 let result = await new Thenable(1); alert(result); } f(); If await gets a non-promise object with .then, it calls that method providing the built-in functions resolve and reject as arguments (just as it does for a regular Promise executor). Then await waits until one of them is called (in the example above it happens in the line (*)) and then proceeds with the result. Async class methods To declare an async class method, just prepend it with async: class Waiter { async wait() { return await Promise.resolve(1); } } new Waiter() .wait() .then(alert); // 1 (this is the same as (result => alert(result))) The meaning is the same: it ensures that the returned value is a promise and enables await. Error handling If a promise resolves normally, then await promise returns the result. But in the case of a rejection, it throws the error, just as if there were a throw statement at that line. This code: async function f() { await Promise.reject(new Error("Whoops!")); } …is the same as this: async function f() { throw new Error("Whoops!"); } In real situations, the promise may take some time before it rejects. In that case there will be a delay before await throws an error. We can catch that error using try..catch, the same way as a regular throw: async function f() { try { let response = await fetch(' } catch(err) { alert(err); // TypeError: failed to fetch } } f(); In the case of an error, the control jumps to the catch block. We can also wrap multiple lines: async function f() { try { let response = await fetch('/no-user-here'); let user = await response.json(); } catch(err) { // catches errors both in fetch and response.json alert(err); } } f(); If we don’t have try..catch, then the promise generated by the call of the async function f() becomes rejected. We can append .catch to handle it: async function f() { let response = await fetch('} // f() becomes a rejected promise f().catch(alert); // TypeError: failed to fetch // (*) If we forget to add .catch there, then we get an unhandled promise error (viewable in the console). We can catch such errors using a global unhandledrejection event handler as described in the chapter Error handling with promises. async/await and promise.then/catch When we use async/await, we rarely need .then, because await handles the waiting for us. And we can use a regular try..catch instead of .catch. That’s usually (but not always) more convenient. But at the top level of the code, when we’re outside any async function, we’re syntactically unable to use await, so it’s a normal practice to add .then/catch to handle the final result or falling-through error, like in the line (*) of the example above. async/await works well with Promise.all When we need to wait for multiple promises, we can wrap them in Promise.all and then await: // wait for the array of results let results = await Promise.all([ fetch(url1), fetch(url2), ... ]); In the case of an error, it propagates as usual, from the failed promise to Promise.all, and then becomes an exception that we can catch using try..catch around the call. Summary The async keyword before a function has two effects: Makes it always return a promise. Allows await to be used in it. The await keyword before a promise makes JavaScript wait until that promise settles, and then: If it’s an error, the exception is generated — same as if throw error were called at that very place. Otherwise, it returns the result. Together they provide a great framework to write asynchronous code that is easy to both read and write. With async/await we rarely need to write promise.then/catch, but we still shouldn’t forget that they are based on promises, because sometimes (e.g. in the outermost scope) we have to use these methods. Also Promise.all is nice when we are waiting for many tasks simultaneously. Tasks Rewrite using async/await Rewrite this example code from the chapter Promises chaining using async/await instead of .then/catch: function loadJson(url) { return fetch(url) .then(response => { if (response.status == 200) { return response.json(); } else { throw new Error(response.status); } }); } loadJson('no-such-user.json') .catch(alert); // Error: 404 solution Rewrite "rethrow" with async/await Below you can find the “rethrow” example. Rewrite it using async/await instead of .then/catch. And get rid of the recursion in favour of a loop in demoGithubUser: with async/await that becomes easy to do. class constructor(response) { super(`${response.status} for ${response.url}`); this.name = ' this.response = response; } } function loadJson(url) { return fetch(url) .then(response => { if (response.status == 200) { return response.json(); } else { throw new } }); } // Ask for a user name until github returns a valid user function demoGithubUser() { let name = prompt("Enter a name?", "iliakan"); return loadJson(` .then(user => { alert(`Full name: ${user.name}.`); return user; }) .catch(err => { if (err instanceof alert("No such user, please reenter."); return demoGithubUser(); } else { throw err; } }); } demoGithubUser(); solution Call async from non-async We have a “regular” function called f. How can you call the async function wait() and use its result inside of f? async function wait() { await new Promise(resolve => setTimeout(resolve, 1000)); return 10; } function f() { // ...what should you write here? // we need to call async wait() and wait to get 10 // remember, we can't use "await" } P.S. The task is technically very simple, but the question is quite common for developers new to async/await.

    Asynchronous - True or False?

    To send the request asynchronously, the async parameter of the open() method has to be set to true: xmlhttp.open("GET", "xmlhttp_info.txt", true); Sending asynchronously requests is a huge improvement for web developers. Many of the tasks performed on the server are very time consuming. By sending asynchronously, the JavaScript does not have to wait for the server response, but can instead: execute other scripts while waiting for server response deal with the response when the response is ready

    Async = true

    When using async = true, specify a function to execute when the response is ready in the onreadystatechange event:

    Example

    xmlhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
    document.getElementById("demo").innerHTML = this.responseText;
    }
    };
    xmlhttp.open("GET", "xmlhttp_info.txt", true);
    xmlhttp.send(); Try it Yourself »

    Async = false

    To use async = false, change the third parameter in the open() method to false: xmlhttp.open("GET", "xmlhttp_info.txt", false); Using async = false is not recommended, but for a few small requests this can be ok. Remember that the JavaScript will NOT continue to execute, until the server response is ready. If the server is busy or slow, the application will hang or stop. Note: When you use async = false, do NOT write an onreadystatechange function - just put the code after the send() statement:

    Example

    xmlhttp.open("GET", "xmlhttp_info.txt", false);
    xmlhttp.send();
    document.getElementById("demo").innerHTML = xmlhttp.responseText;Try it Yourself »

    variables in asynchronous callback functions

    What’s the problem? First let’s assume you have declared a variable called myVar: var myVar; If you immediately log the contents of the variable, it will return undefined. Now if you define any of the following: setTimeout(function() { myVar = "some value"; }, 0); or: $.ajax({ url: '...', success: function(response) { myVar = response; } }); or: var script = document.createElement("script"); script.type = "text/javascript"; script.src = "myscript.js"; script.onload = function(){ myVar = "some value"; }; document.body.appendChild(script); and immediately afterwards display the contents of myVar, you will also get undefined as result. Why is the variable not set? In all examples above, the function defined are what’s called asynchronous callbacks. This means that they are immediately created but not immediately executed. setTimeout pushes it into the event queue, the AJAX calls will execute it once the call returns and onload will be executed when the DOM element is loaded. In all three cases, the function does not execute right away but rather whenever it is triggered asynchronously. So when you log or display the contents of the variable, the function has not yet run and the content has not yet been set. So even though JavaScript actually works with a single-thread model, you’ve landed in the asynchronous problem zone. Synchronous vs. Asynchronous Basically the difference between a synchronous function call and an asynchronous one can be shown with these 2 pieces of code: var myVar; function doSomething() { myVar = "some value"; } doSomething(); //synchronous call log(myVar); And: var myVar; function doSomething() { myVar = "some value"; } log(myVar); doSomething(); //asynchronous call In the asynchronous case, our function is also defined before logging the variable but is call some time later. How to make it work? You will need to rewrite your code in order to use callbacks which will be called when the processing (in this case setting the value of myVar) is done. First example: Instead of using the following: var myVar; setTimeout(function() { myVar = "some value"; }, 0); alert(myVar); You should rather do the following: var myVar; function callback() { alert(myVar); } setTimeout(function() { myVar = "some value"; callback(); }, 0); Instead of this: var myVar; var script = document.createElement("script"); script.type = "text/javascript"; script.src = "d3.min.js"; script.onload = function(){ myVar = "some value"; }; document.body.appendChild(script); alert(myVar); Use this: function callback(response) { alert("loaded"); } var script = document.createElement("script"); script.type = "text/javascript"; script.src = "d3.min.js"; script.onload = callback; document.body.appendChild(script); And instead of doing the following: var myVar; $.ajax({ url: '...', success: function(response) { myVar = response; } }); alert(myVar); Do the following: function callback(response) { alert(response); } $.ajax({ url: '...', success: callback }); Of course, here another solution is to make the AJAX call synchronous by adding the following to the options: async: false Also if you use $.get or $.post, you’ll need to rewrite it to use $.ajax instead. But this is not a good idea. First if the call lasts longer than expected, you will block the UI making your browser window unresponsive. And at some point in the time the browser will ask your user whether you want to stop the unresponsive script. So, even though programing everything in an asynchronous way with callbacks is not always trivial, doing everything in a synchronous way will cause more sporadic and difficult to handle issues. So to summarize, you should either use a callback or directly call a function after processing and not only rely on setting a variable in the asynchronous part. variables in asynchronous callback functions onload function with return My function does not return value

    One-Liner JavaScript



    Shuffle Array

    const shuffleArray = (arr) => arr.sort(() => Math.random() - 0.5); // Testing const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; console.log(shuffleArray(arr));

    Unique Elements

    const getUnique = (arr) => [...new Set(arr)]; // Testing const arr = [1, 1, 2, 3, 3, 4, 4, 4, 5, 5]; console.log(getUnique(arr));

    Detect Dark Mode

    const isDarkMode = () =>window.matchMedia &&window.matchMedia("(prefers-color-scheme: dark)").matches; // Testing console.log(isDarkMode());

    Scroll To Top

    const scrollToTop = (element) =>element.scrollIntoView({ behavior: "smooth", block: "start" });

    Scroll To Bottom

    const scrollToBottom = (element) =>element.scrollIntoView({ behavior: "smooth", block: "end" });

    Generate Random Color

    const generateRandomHexColor = () =>`#${Math.floor(Math.random() * 0xffffff).toString(16)}`;

    this Keyword

    In JavaScript, the <k>this</k> keyword refers to an object. The <k>this</k> keyword refers to different objects depending on how it is used: Methods like call(), apply(), and bind() can refer this to any object. Example const person = { firstName: "John", lastName : "Doe", id : 5566, fullName : function() { return this.firstName + " " + this.lastName; } }; When used alone, this refers to the global object. <k>this</k> in Event Handlers Example <button onclick="this.style.display='none'"> Click to Remove Me! </button> Example const person = { firstName : "John", lastName : "Doe", id : 5566, myFunction : function() { return this; } }; Example const person = { firstName: "John", lastName : "Doe", id : 5566, fullName : function() { return this.firstName + " " + this.lastName; } }; Example const person1 = { fullName: function() { return this.firstName + " " + this.lastName; } } const person2 = { firstName:"John", lastName: "Doe", } // Return "John Doe": person1.fullName.call(person2);

    to list all memory variavles

    for(var b in window) { if(window.hasOwnProperty(b)) console.log(b); }

    codes to be studied

    appendChild() select() execCommand() remove(); all = $('*').not('script, meta, link, style, noscript, title') (document).on('mousemove', function(e) { let cordinate_x = e.pageX; let cordinate_y = e.pageY; let windowWidth = $(window).width(); if (cordinate_y < tooltip.outerHeight()) { tooltip.css({'top': (cordinate_y + 10) + 'px'}); tooltip.addClass(tooltipClass); $(window).on('keyup', function(e) { let keyCode = e.keyCode ? e.keyCode : e.which; if (keyCode == 44) {stopPrntScr(); audio_play(); $(document).on('contextmenu', function(e) { let target = $(event.target); if (target.is("img") || target.is("div.ays_tooltip_class")) {let t = e || window.event; let n = t.target || t.srcElement; if (n.nodeName !== "A") { show_tooltip(1 ); $(document).on('dragstart', function() { let target = $(event.target); if (!target.is("")) {show_tooltip(1 ); $(window).on('keydown', function(event) { var sccp_selObj = window.getSelection(); if (!sccp_selObj.rangeCount < 1) {var sccp_selRange = sccp_selObj.getRangeAt(0); sccp_selection_selector = sccp_selRange.startContainer.parentElement; check_selectors = !$(sccp_selection_selector).is(""); if (check_selectors) {var isOpera = (BrowserDetect.browser === "Opera"); var isFirefox = (BrowserDetect.browser === 'Firefox'); var isSafari = (BrowserDetect.browser === 'Safari'); var isIE = (BrowserDetect.browser === 'Explorer'); var isChrome = (BrowserDetect.browser === 'Chrome'); var isMozilla = (BrowserDetect.browser === 'Mozilla'); if (BrowserDetect.OS === 'Windows') { if (isChrome) { if (((event.ctrlKey && event.shiftKey) && ( event.keyCode === 73 || event.keyCode === 74 || event.keyCode === 68 || event.keyCode === 67))) { show_tooltip(1); if (isFirefox) { if (((event.ctrlKey && event.shiftKey) && ( event.keyCode === 73 || event.keyCode === 74 || event.keyCode === 67 || event.keyCode === 75 || event.keyCode === 69)) || event.keyCode === 118 || (event.keyCode === 112 && event.shiftKey) || (event.keyCode === 115 && event.shiftKey) || (event.keyCode === 118 && event.shiftKey) || (event.keyCode === 120 && event.shiftKey)) { show_tooltip(1); if (isOpera) { if (((event.ctrlKey && event.shiftKey) && ( event.keyCode === 73 || event.keyCode === 74 || event.keyCode === 67 || event.keyCode === 88 || event.keyCode === 69))) { show_tooltip(1); if (isIE) { if ((event.keyCode === 123 && event.shiftKey)) { show_tooltip(1); if (isMozilla) { if ((event.ctrlKey && event.keyCode === 73) || (event.altKey && event.keyCode === 68)) { show_tooltip(1); if (BrowserDetect.OS === 'Linux') { if (BrowserDetect.OS === 'Mac') { if (isChrome || isSafari || isOpera || isFirefox) function disableSelection(e) { if (typeof e.onselectstart !== "undefined")e.onselectstart = function() { show_tooltip( ); audio_play(); return false}; else if (typeof e.style.MozUserSelect !== "undefined")e.style.MozUserSelect = "none"; else e.onmousedown = function() { show_tooltip(); e.style.cursor = "default"} $('#ays_tooltip').fadeOut(); function copyToClipboard(text) { var textarea = document.createElement("textarea"); catch (ex) {console.warn("Copy to clipboard failed.", ex); document.body.removeChild(textarea); function htmlDecode(input) { var doc = new DOMParser().parseFromString(input, "text/html"); return doc.documentElement.textContent; this.version = this.searchVersion(navigator.userAgent) this.OS = this.searchString(this.dataOS) parseFloat(dataString.substring(index + this.versionSearchString.length + 1));

    execCommand()

    Year 2022 answer: The execCommand() is officially obsolete/deprecated but there's no alternative. So if you must have rich text support, you have to keep using execCommand() and figure out yourself what actually works with browsers that you want to support. Note that real world user agents (browsers such as Chrome, Firefox and Safari) cannot drop support for execCommand() because so many services require support for it. The sad state of things is that HTML5 cannot specify any common ground. This is because browser vendors do not agree how execCommand() should work. So nothing can be specified for HTML5, which has the overall objective to specify all stuff – and only stuff – that's needed for full interoperability for any new browser to enter market. HTML5 fails here because execCommand() compatibility is actually required for any new browser to enter market. So it would make sense to standardize at least one of the browser specific implementations as the official one. All the current standardization efforts (Input Events 2, Clipboard API) fail to even try to cover the features that execCommand() actually does (for example, undo/redo, actually changing content within the selection range). The hardest part to solve is the caret movement, selecting text, different IME (Input Method Editor) behavior and handling native clipboard. These all interact with each other in various ways depending on browser and operating system. For example, the behavior that iOS Safari has on iPad while writing Traditional Chinese is totally different from Firefox on Windows with Thai IME. Which is again totally different from Chrome running on Chromebook while writing Finnish or entering emoji characters with multiple UNICODE point encoding. And as none of the available JS APIs disclose all the details, you MUST use contenteditable and possibly execCommand(), too, for most browsers to get correct input from the IME. Also note that e.g. Android GBoard needs to also know about the surrounding text within the same editable content because it uses AI logic to correctly figure out which word suggestions to give to the user while inputting text, so you cannot fake this with a single empty invisible textarea under the caret because that would be missing the required context. That hasn't prevented people from trying to do exactly that but it fails in practice in various ways. Syntax

    Timer

    var shell = WScript.CreateObject("WScript.Shell"); // 定义定时器持续时间(毫秒) var timerDuration = 5000; // 5秒 // 定义重复次数 var repeatCount = 3; // 重复3次 // 循环执行指定次数 for (var i = 1; i <= repeatCount; i++) { // 显示消息框 shell.Popup("定时器已到期!", 0, "定时器"); // 等待指定的持续时间 WScript.Sleep(timerDuration); } 在这个 JavaScript 示例中,我们使用 WScript.CreateObject 方法创建了 WScript.Shell 对象,然后使用该对象的 Popup 方法显示一个消息框。 使用 WScript.Sleep 方法来实现定时器的延迟。 将代码保存为 .js 文件,并使用 Windows Script Host (WSH) 运行该文件。 它会在指定的时间间隔后弹出消息框,并按照设置的重复次数重复显示。 请注意,这段代码使用的是 Windows Script Host (WSH),而不是在浏览器中运行的标准 JavaScript。 因此,在命令行或通过脚本运行该文件时,确保系统中已安装并配置了 WSH。

    要在浏览器中运行 JavaScript 编写定时闹钟

    使用 setTimeout 函数来实现定时器功能。 function setAlarm(alarmTime) { var currentTime = new Date().getTime(); var alarmDateTime = new Date(alarmTime).getTime(); var timeDifference = alarmDateTime - currentTime; if (timeDifference > 0) { setTimeout(function() { alert("闹钟时间到!"); }, timeDifference); } else { alert("闹钟时间必须晚于当前时间!"); } } // 设置闹钟时间 var alarmTime = "2023-11-13T08:00:00"; // 闹钟时间,格式为 "YYYY-MM-DDTHH:mm:ss" // 调用设置闹钟函数 setAlarm(alarmTime); 在这个示例中,setAlarm 函数接受一个闹钟时间作为参数。 它首先获取当前时间和闹钟时间的时间戳,并计算它们之间的时间差(以毫秒为单位)。 如果时间差大于零,则使用 setTimeout 函数在时间差之后触发弹窗提醒。 如果时间差小于等于零,则显示一个错误提示。 您可以将闹钟时间作为字符串传递给 setAlarm 函数,并按照 "YYYY-MM-DDTHH:mm:ss" 的格式设置时间。 请注意,日期和时间之间使用 "T" 分隔。 在浏览器的控制台中运行这段代码,它将设置一个定时闹钟,并在指定的闹钟时间到达时触发弹窗提醒。

    webscraper

    Node-crawler https://github.com/bda-research/node-crawler 支持非阻塞异步I/O,实现爬虫的流水线运行机制。 同时支持DOM的快速选取(无需编写正则表达式)。 服务器端使用Cheerio(默认)或JSDOM实现jQuery自动插入DOM EasySpider https://github.com/NaiboWang/EasySpider 可以使用图形化界面,无代码可视化的设计和执行任务。 同时软件还可以单独以命令行的方式进行执行,从而可以很方便地嵌入到其他系统中。

    Creates a copy of the array

    var tempArray = testArray.slice(); creating a reference to testArray: var tempArray = testArray; Basically tempArray is just another name for the same object. to create a copy of the array use slice() which copies the data in testArray. This is an issue of pass by reference, vs pass by value -- it very much varies language to language.

    To pass data from one application to a browser



    Introduction


    It is possible to pass data from one application to a browser through shared memory or inter-process communication (IPC) mechanisms. Here are a few common approaches:  Shared Memory:
    Applications can create a shared memory region that is accessible by multiple processes. One application can write data to this shared memory, and the browser can read it. The data can be structured in a specific format, such as JSON or binary, to ensure compatibility between the applications.  WebSocket:
    WebSocket is a communication protocol that provides full-duplex communication channels over a single TCP connection. An application can establish a WebSocket connection with the browser, allowing bidirectional communication. The application can then send data to the browser in real-time.  Local Server:
    An application can act as a local server and expose an API or web service. The browser can send HTTP requests to this local server, passing the data as part of the request payload or query parameters. The application can then process the request and respond with the necessary data.  Inter-Process Communication (IPC):
    IPC mechanisms like named pipes, Unix domain sockets, or message queues can be used to facilitate communication between the application and the browser. The application can send messages or data to the browser using the chosen IPC mechanism, and the browser can receive and process them accordingly. It's important to note that the specific implementation details may vary depending on the operating system, programming languages, and frameworks being used. Each approach has its own advantages and considerations, so the choice of method depends on the specific requirements and constraints of your application.

    using Python


    Here's an example using Python to demonstrate how to pass data from one application to a browser through shared memory: Application (Data Producer): python import mmap # Open or create a shared memory region shm = mmap.mmap(-1, 1024, "SharedMemName") # Write data to the shared memory data = b"Hello, browser!" shm.write(data) # Close the shared memory shm.close() Browser (Data Consumer): javascript // Create an XMLHttpRequest object var xhr = new XMLHttpRequest(); // Open a GET request to the server endpoint that reads the shared memory xhr.open('GET', '/readSharedMemory', true); // Set the response type to 'arraybuffer' xhr.responseType = 'arraybuffer'; // Handle the response xhr.onload = function() { // Retrieve the shared memory data var sharedData = new Uint8Array(xhr.response); // Convert the shared memory data to a string var text = String.fromCharCode.apply(null, sharedData); // Display the data in the browser console console.log(text); }; // Send the request xhr.send(); In this example, the application (Data Producer) creates a shared memory region using the mmap module in Python. It writes the data (in this case, the string "Hello, browser!") to the shared memory region. On the browser side (Data Consumer), an XMLHttpRequest is used to send a GET request to a server endpoint (e.g., /readSharedMemory). The server reads the shared memory and returns the data as an ArrayBuffer in the response. The response data is then converted to a string and displayed in the browser console. Please note that this is a simplified example for demonstration purposes, and the actual implementation may vary based on your specific requirements and programming environment.

    using R


    Here's an example using R to demonstrate how to pass data from R to a browser through shared memory: Application (Data Producer) - R script: # Install required packages if not already installed if (!require("Rcpp")) install.packages("Rcpp") # Load the required libraries library(Rcpp) library(RcppParallel) # Define a function to write data to shared memory writeToSharedMemory <- function(data) { # Convert the data to raw bytes raw_data <- charToRaw(data) # Create a shared memory object shared_memory <- SharedMemory$new("SharedMemName", length(raw_data)) # Write the data to shared memory shared_memory$write(0, raw_data) # Release the shared memory object shared_memory$detach() } # Call the function to write data to shared memory writeToSharedMemory("Hello, browser!") Browser (Data Consumer) - JavaScript: // Create an XMLHttpRequest object var xhr = new XMLHttpRequest(); // Open a GET request to the server endpoint that reads the shared memory xhr.open('GET', '/readSharedMemory', true); // Set the response type to 'arraybuffer' xhr.responseType = 'arraybuffer'; // Handle the response xhr.onload = function() { // Retrieve the shared memory data var sharedData = new Uint8Array(xhr.response); // Convert the shared memory data to a string var text = String.fromCharCode.apply(null, sharedData); // Display the data in the browser console console.log(text); }; // Send the request xhr.send(); In this example, the R script (Data Producer) uses the Rcpp and RcppParallel libraries to create a shared memory object and write data to it. The writeToSharedMemory function converts the data (in this case, the string "Hello, browser!") to raw bytes and writes it to the shared memory region. On the browser side (Data Consumer), an XMLHttpRequest is used to send a GET request to a server endpoint (e.g., /readSharedMemory). The server reads the shared memory and returns the data as an ArrayBuffer in the response. The response data is then converted to a string and displayed in the browser console. Please note that this example assumes you have the necessary R packages (Rcpp and RcppParallel) installed. Additionally, the server-side implementation that reads the shared memory and serves it to the browser needs to be implemented separately based on your specific web framework or server environment.

    using JavaScript


    In JavaScript, there is no built-in mechanism for directly sharing memory between different browser tabs or windows. However, you can use other techniques to pass data between JavaScript instances running in different tabs or windows of the same browser. One such technique is using the localStorage object to share data. Here's an example: Sending data from JavaScript in one tab/window: javascript // Set the data in localStorage localStorage.setItem('sharedData', 'Hello, other tab!'); Receiving data in JavaScript in another tab/window: javascript // Listen for changes to localStorage window.addEventListener('storage', function(event) { if (event.key === 'sharedData') { // Retrieve the shared data var sharedData = event.newValue; // Do something with the shared data console.log(sharedData); } }); In this example, the first JavaScript instance sets the data in the localStorage object using the setItem method. The key for the data is 'sharedData', and the value is 'Hello, other tab!'. The second JavaScript instance listens for changes to the localStorage object using the storage event. When the event is triggered, it checks if the event key is 'sharedData'. If it matches, it retrieves the shared data from event.newValue and can then perform any necessary operations with the shared data. Please note that this technique is limited to sharing data within the same browser, and it has some limitations such as storage capacity restrictions and the requirement for the events to be triggered by changes in the localStorage object.

    using Node.js


    In Node.js, you can use the shared-memory package to create and manage shared memory regions, allowing you to pass data from Node.js to a browser. Here's an example: Install the required package: shell npm install shared-memory Node.js Server (Data Producer): javascript const sharedMemory = require('shared-memory'); // Create or open a shared memory region const shm = sharedMemory.create('SharedMemName', 1024); // Write data to the shared memory const data = 'Hello, browser!'; shm.write(data); // Close the shared memory shm.close(); Browser (Data Consumer) - JavaScript: // Create an XMLHttpRequest object var xhr = new XMLHttpRequest(); // Open a GET request to the server endpoint that reads the shared memory xhr.open('GET', '/readSharedMemory', true); // Set the response type to 'arraybuffer' xhr.responseType = 'arraybuffer'; // Handle the response xhr.onload = function() { // Retrieve the shared memory data var sharedData = new Uint8Array(xhr.response); // Convert the shared memory data to a string var text = String.fromCharCode.apply(null, sharedData); // Display the data in the browser console console.log(text); }; // Send the request xhr.send(); In this example, the Node.js server (Data Producer) uses the shared-memory package to create or open a shared memory region with the name 'SharedMemName' and a size of 1024 bytes. It then writes the data (in this case, the string 'Hello, browser!') to the shared memory region. On the browser side (Data Consumer), an XMLHttpRequest is used to send a GET request to a server endpoint (e.g., /readSharedMemory). The server reads the shared memory and returns the data as an ArrayBuffer in the response. The response data is then converted to a string and displayed in the browser console. Please note that this example assumes you have installed the shared-memory package and have a Node.js server set up to handle the HTTP requests. The server-side implementation that reads the shared memory and serves it to the browser needs to be implemented separately based on your specific server environment.

    call a function when a javascript variable changed

    In JavaScript, there is no built-in mechanism to directly detect changes in a variable. However, you can create a custom setter function or use a JavaScript Proxy object to achieve this behavior. Here's an example using a setter function: javascript // Create a variable with an initial value let myVariable = 0; // Create a setter function for the variable function setMyVariable(value) { myVariable = value; // Call your function here yourFunction(); } // Assign the setter function to the variable myVariable = setMyVariable; // Your function to be called when the variable changes function yourFunction() { console.log('Variable has changed!'); } // Update the variable's value myVariable = 10; // This will trigger the setter function and call yourFunction() In this example, we define a variable myVariable and a setter function setMyVariable to update its value. Whenever you assign a new value to myVariable, it will actually call the setMyVariable function, which in turn updates the value and calls yourFunction. This way, you can ensure that yourFunction is invoked whenever the variable changes. You may need to adapt this approach depending on your specific use case and how the variable is being accessed or modified in your code.

    To run a function after an element has changed without continuously running the function

    Make use of JavaScript's MutationObserver API. The MutationObserver allows you to watch for changes in a specific DOM element and trigger a callback function when the changes occur. Here's an example of how you can use the MutationObserver to achieve this: javascript // Select the target element const targetElement = document.getElementById('your-element-id'); // Create a new MutationObserver const observer = new MutationObserver(function(mutationsList, observer) { // Check if the mutations include the desired changes for (let mutation of mutationsList) { if (mutation.type === 'attributes' && mutation.attributeName === 'class') { // Call your function here yourFunction(); // Disconnect the observer after the change is detected observer.disconnect(); break; } } }); // Start observing the target element for changes observer.observe(targetElement, { attributes: true }); // Your function to be called when the element changes function yourFunction() { console.log('Element has changed!'); } In this example, the MutationObserver is created and attached to the target element using the observe method. In the callback function, you can check for specific types of mutations (in this case, attribute changes) and execute your desired function. Once the change is detected, you can disconnect the observer using the disconnect method to stop further observations. Make sure to replace 'your-element-id' with the actual ID of the element you want to monitor, and customize the yourFunction function to perform the desired actions when the element changes.

    Use browser javascript to write file to local drive

    In a web browser environment, JavaScript doesn't have direct access to the local file system for security reasons. However, you can achieve file writing functionality using a combination of JavaScript and other web technologies. One common approach is to use the File API and the download attribute on an anchor tag. Here's an example: html <!DOCTYPE html> <html> <head><title>File Writing Example</title></head> <body> <button onclick="saveToFile()">Save Text to File</button> <script> function saveToFile() { var textToWrite = "This is the content of the file."; var element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(textToWrite)); element.setAttribute('download', 'myfile.txt'); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); } </script> </body> </html> In this example, we create a button with the onclick event that triggers the saveToFile function. Inside the function, we create a new anchor element using document.createElement('a'). We set the href attribute to a data URL that contains the text content we want to save. The download attribute specifies the filename for the downloaded file. We then append the anchor element to the document body, trigger a click event on it programmatically using element.click(), and finally remove the element from the document. When the user clicks the button, their browser will download the file with the specified content as a text file. The user will be prompted to save the file to their local drive. If you have a web page running locally on your computer, you can use JavaScript to write a file to the local drive. However, it requires additional steps and is not as straightforward as the previous example. To write a file to the local drive, you can use the File System API, which is available in some modern browsers. Here's an example of how you can use the File System API to write a file: html <!DOCTYPE html> <html> <head> <title>Local File Writing Example</title> </head> <body> <button onclick="saveToFile()">Save Text to File</button> <script> function errorHandler(err) { console.error('Error:', err); } function saveToFile() { var textToWrite = "This is the content of the file."; window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; window.requestFileSystem( window.PERSISTENT, 5 * 1024 * 1024, // 5MB storage space function(fs) { fs.root.getFile( 'myfile.txt', { create: true }, function(fileEntry) { fileEntry.createWriter( function(fileWriter) { fileWriter.onwriteend = function() { console.log('File saved successfully.'); }; fileWriter.onerror = errorHandler; var blob = new Blob([textToWrite], { type: 'text/plain' }); fileWriter.write(blob); }, errorHandler ); }, errorHandler ); }, errorHandler ); } </script> </body> </html> In this example, we use the requestFileSystem method to request access to the file system. We then specify the storage space size (5MB in this case) and provide a success callback function and an error callback function. Inside the success callback, we use fs.root.getFile to create or access the file. We pass the filename as 'myfile.txt', and { create: true } to ensure the file is created if it doesn't exist. Once we have the fileEntry, we call fileEntry.createWriter to create a FileWriter object. We set up event handlers for onwriteend and onerror to handle the write operation's success or failure. We create a Blob object containing the text content to be written, specifying the MIME type as 'text/plain'. Then we call fileWriter.write to write the Blob to the file. When the user clicks the button, the JavaScript code will attempt to write the file to the local drive using the File System API. Please note that the availability and support for the File System API may vary among different browsers, and it may require specific permissions or additional configurations to work properly.

    To save a file from a web browser by making a request to a Node.js server

    Set up a Node.js server: Create a Node.js server using a framework like Express.js or the built-in http module. Set up a route to handle the file-saving request. Handle the file-saving request on the server: In the server route handler, receive the file content from the browser request and save it to the server's file system using Node.js's built-in fs module. Send a response to the browser: Once the file is saved successfully or encounters an error, send a response back to the browser to indicate the status of the file-saving operation. Here's an example to illustrate this process: Node.js Server: javascript const express = require('express'); const fs = require('fs'); const app = express(); const PORT = 3000; app.post('/savefile', (req, res) => { let fileData = ''; req.on('data', (chunk) => { fileData += chunk; }); req.on('end', () => { // Save the file to the server's file system fs.writeFile('path/to/save/file.txt', fileData, (err) => { if (err) { console.error('Error saving file:', err); res.status(500).send('Error saving file'); } else { console.log('File saved successfully'); res.send('File saved successfully'); } }); }); }); app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); }); In this example, we set up an Express.js server listening on port 3000. The /savefile route is configured to handle POST requests. Inside the route handler, we listen to the data event of the request object to receive the file content sent by the browser. We concatenate the received chunks of data into a single string variable fileData. When the request ends (end event), we use fs.writeFile to save the file to the server's file system. Adjust the file path in the writeFile function to the desired location where you want to save the file. If the file saving is successful, we send a response with status code 200 and the message "File saved successfully" back to the browser. If an error occurs during the file-saving operation, we send a response with status code 500 and the message "Error saving file". On the browser side, you need to make an HTTP POST request to the server's /savefile route, sending the file content. You can use JavaScript's fetch API or other AJAX libraries to accomplish this. Here's an example using fetch: Browser JavaScript: javascript function saveFileToServer() { var fileContent = 'This is the content of the file.'; fetch('/savefile', { method: 'POST', body: fileContent }) .then(response => { if (response.ok) { console.log('File saved on the server'); } else { console.error('Error saving file on the server'); } }) .catch(error => { console.error('Error:', error); }); } saveFileToServer(); In this example, we define the saveFileToServer function, which sends an HTTP POST request to the server's /savefile route. We pass the file content as the request body. When the server responds, we check the response's status code. If it's successful (status code 200), we log the message "File saved on the server". Otherwise, we log the error message "Error saving file on the server" in case of an unsuccessful response or connection failure. Make sure to adjust the server URL ('/savefile') in the fetch request based on your server's configuration. With these steps, you can save a file from a web browser by making a request to a Node.js server.

    To draw stock OHLC charts using JavaScript

    One popular library for this purpose is Chart.js. Here's a step-by-step guide on how to use Chart.js to draw OHLC charts: Step 1: Include Chart.js Library Add the Chart.js library to your HTML file by including the following script tag: html <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> Step 2: Prepare HTML Canvas Element Create an HTML canvas element where the chart will be rendered. Make sure to give it an ID for easy reference: html <canvas id="ohlcChart"></canvas> Step 3: Retrieve Stock Data Fetch or retrieve the stock data that contains OHLC values. You can use an API or a data source of your choice to obtain the required data. Step 4: Prepare Data for Chart.js Convert the retrieved stock data into a format that Chart.js can understand. The data should be organized as an array of objects, with each object representing a data point. Each object should have properties for t (timestamp), o (open), h (high), l (low), and c (close). For example: javascript const stockData = [ { t: 1630518000000, o: 100, h: 110, l: 90, c: 105 }, { t: 1630604400000, o: 105, h: 115, l: 95, c: 112 }, // Add more data points... ]; example: const ohlcData = [ { x: Date.parse('2023-08-01'), o: 221.13, h: 222.99, l: 222.13, c: 221.31 }, { x: Date.parse('2023-08-02'), o: 221.13, h: 222.99, l: 222.13, c: 222.31 }, // Add more data points... ]; Step 5: Create OHLC Chart Initialize a new Chart.js chart instance and configure its options and data using the stock data prepared in the previous step: javascript // Get the canvas element const canvas = document.getElementById('ohlcChart'); // Create the OHLC chart const ohlcChart = new Chart(canvas, { type: 'candlestick', data: { datasets: [{ label: 'Stock Data', data: stockData, borderColor: 'rgba(0, 0, 0, 1)', borderWidth: 1 }] }, options: { // Configure chart options as needed // For example, you can set the chart title, axis labels, etc. // Refer to Chart.js documentation for available options } }); Step 6: Customize and Style the Chart You can further customize the chart's appearance and style by modifying the options object passed to the Chart.js chart instance. For example, you can change the colors, add tooltips, set axis labels, and more. Refer to the Chart.js documentation for a comprehensive list of available options and customization possibilities. That's it! With these steps, you can draw stock OHLC charts using JavaScript and Chart.js. Remember to adjust the code according to your specific data and requirements.

    Cross-Origin Resource Sharing

    In a web browser, the JavaScript CORS (Cross-Origin Resource Sharing) policy restricts requests made from a webpage to resources located on a different domain. This policy exists for security reasons and cannot be bypassed directly from JavaScript code. However, if you have control over the server hosting the JavaScript file and can modify its configuration, you can enable CORS on the server to allow requests from the domain where your webpage is hosted. This requires making changes on the server-side, not within the JavaScript code itself. Assuming you have control over the server, here's how you can enable CORS for a JavaScript file: Configure the server: Modify the server configuration to include the appropriate CORS headers. This process depends on the server technology you are using. For example, if you're using Apache, you can set the CORS headers in the .htaccess file or the server configuration file. Here's an example of setting CORS headers in Apache: apache Header set Access-Control-Allow-Origin "*" The above example allows requests from any domain (*). You can replace * with the specific domain(s) from where you want to allow requests. Restart the server: After making the configuration changes, restart the server for the changes to take effect. Once CORS is enabled on the server, you should be able to load the JavaScript file from a different domain without encountering CORS restrictions. Keep in mind that bypassing the CORS policy may have security implications, so it's essential to understand the risks and only enable CORS when necessary and with the appropriate security measures in place.

    Inspect autoload

    Right-click on the webpage and select "Inspect" or "Inspect Element" from the context menu. This will open the browser's developer tools. Navigate to the Network tab: In the developer tools, locate the "Network" tab. This tab will display the network activity of the webpage. Scroll to trigger the autoload: Scroll down on the webpage until the additional images are loaded or until you reach the end of the page where the autoload should occur. Observe network requests: As you scroll, keep an eye on the Network tab. Look for any new network requests that appear in the list while you're scrolling. These requests could indicate the autoload URL or other related requests. Filter and analyze requests: If you see new requests appearing in the Network tab, you can filter the requests by different types (e.g., XHR, Fetch, or Images) to focus on the ones that are relevant. Look for requests that correspond to the loading of images or any requests that seem related to the autoload functionality. Examine request details: Click on the relevant request in the Network tab to view its details. Look for the URL field, which will contain the URL of the autoload request. Additionally, you can inspect the request headers and parameters to understand how the autoload functionality is implemented. By following these steps, you should be able to identify the autoload URL used by the website to load more images at the end of the page. Keep in mind that the exact process may vary slightly depending on the browser you are using, but the general concept remains the same.

    sprite animations

    SPRITE ANIMATIONS drawImage() method: context.drawImage(img,x,y,width,height); define the source rectangle of the image, then define the destination rectangle context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height); context.drawImage(img, 100, 0, 200, 50, 10, 30, 200, 50); a fragment of the image is picked from (100, 0), with a width of 200 and height of 50. The fragment is drawn to (10, 30), with the same width and height as the source. sub image in sprites can be seen as a frame // Define the size of a frame let frameWidth = 50; let frameHeight = 61; // Rows and columns start from 0 let row = 1; let column = 3; context.drawImage(sprite, column*frameWidth, row*frameHeight, frameWidth, frameHeight, 10, 30, frameWidth, frameHeight); Create a sprite animation // Define the number of columns and rows in the sprite let numColumns = 5; let numRows = 2; // Define the size of a frame let frameWidth = sprite.width / numColumns;; let frameHeight = sprite.height / numRows;; // The sprite image frame starts from 0 let numColumns = 1; let numRows = 1; let currentFrame = 0; setInterval(function() { // Pick a new frame currentFrame++; // Make the frames loop let maxFrame = numColumns * numRows - 1; if (currentFrame > maxFrame){ currentFrame = 0; } // Update rows and columns let column = currentFrame % numColumns; let row = Math.floor(currentFrame / numColumns); // Clear and draw context.clearRect(0, 0, canvas.width, canvas.height); context.drawImage(sprite, column * frameWidth, row * frameHeight, frameWidth, frameHeight, 10, 30, frameWidth, frameHeight); //Wait for next step in the loop }, 100); // single row sprite let currentFrame = 0; let maxFrame = 10; setInterval(function() { // Pick a new frame currentFrame++; // Make the frames loop if (currentFrame > maxFrame){ currentFrame = 0; } // Clear and draw context.clearRect(0, 0, canvas.width, canvas.height); context.drawImage(sprite, currentFrame * frameWidth, frameHeight, frameWidth, frameHeight, 10, 30, frameWidth, frameHeight); //Wait for next step in the loop }, 100);

    hide cursor

    document.body.style.cursor = "none"

    videojs

    videojs <script src="https://cdn1d-static-shared.phncdn.com/html5player/videoPlayer/es6player/7.3.3/basic-player.min.js"></script> <video id="my-video" class="video-js" controls preload="auto" width="640" height="264" poster="MY_VIDEO_POSTER.jpg" data-setup="{}" > <source src="MY_VIDEO.mp4" type="video/mp4" /> <source src="MY_VIDEO.webm" type="video/webm" /> <p class="vjs-no-js"> To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="https://videojs.com/html5-video-support/" target="_blank" >supports HTML5 video</a > </p> </video>

    swap images

    $("img").mouseenter(function(){ $(this).attr('src','sample2.png'); }); $("img").mouseleave(function(){ $(this).attr('src','sample1.png'); }); var src = elem.attr('data-original'); var src = elem.attr('src');

    Charts with jQuery and xCharts

    Download There is a new library that makes things easier - xCharts. Today, we are going to use it along with the daterange picker for Twitter Bootstrap, to build a pretty, AJAX-powered chart for your web application that fetches data from a MySQL table.

    The HTML

    The HTML structure of the demo is pretty simple - we have to add elements on the page for the initialization of the chart, and for the date picker. As we are including bootstrap in the page anyway, we can make use of its form styling abilities and icons to make it look good.

    index.php

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Pretty Charts with jQuery and AJAX | Tutorialzine Demo</title> <link href="assets/css/xcharts.min.css" rel="stylesheet"> <link href="assets/css/style.css" rel="stylesheet"> <!-- Include bootstrap css --> <link href="assets/css/daterangepicker.css" rel="stylesheet"> <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.2.2/css/bootstrap.min.css" rel="stylesheet" /> </head> <body> <div id="content"> <form class="form-horizontal"> <fieldset> <div class="input-prepend"> <span class="add-on"><i class="icon-calendar"></i></span> <input type="text" name="range" id="range" /> </div> </fieldset> </form> <div id="placeholder"> <figure id="chart"></figure> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <!-- xcharts includes --> <script src="//cdnjs.cloudflare.com/ajax/libs/d3/2.10.0/d3.v2.js"></script> <script src="assets/js/xcharts.min.js"></script> <!-- The daterange picker bootstrap plugin --> <script src="assets/js/sugar.min.js"></script> <script src="assets/js/daterangepicker.js"></script> <!-- Our main script file --> <script src="assets/js/script.js"></script> </body> </html> We are including a good deal of external resources here. In the head section, we have the css files for xcharts, the datepicker, bootstrap (included from cloudflare's super fast cdn), and our style.css file. Before the closing body tag, we have the jQuery library, d3.js (required by xcharts), xcharts, the elegant sugar.js library (required by the date range plugin), the date range plugin and our script.js. In the next steps you will see how all of these work together.

    The MySQL Table

    As I mentioned in the intro, the script we are writing will fetch its data from a MySQL table and display it on the chart. You can find the SQL code that will create the table in schema.sql in the zip file, available for download from the buttons above. This is what the table looks like: It has only three fields. The date field is assigned a unique index, which means that there cannot be duplicate records for the same day. The sales_ord field holds the number of sales for the day. Your database will surely differ, but as long as you return the correct JSON response from your PHP script, there won't be any problems (more on that in the next section). Note: Remember to enter your MySQL connection details in setup.php. You will then have to create a new MySQL database, and import schema.sql from phpMyAdmin or your management system of choice.

    The PHP Code

    In our PHP script, we will select the records from the table that correspond to the passed start and end date, assemble an array, and output it as a JSON:

    ajax.php

    header('Content-Type: application/json'); // Set up the ORM library require_once('setup.php'); if (isset($_GET['start']) AND isset($_GET['end'])) { $start = $_GET['start']; $end = $_GET['end']; $data = array(); // Select the results with Idiorm $results = ORM::for_table('chart_sales') ->where_gte('date', $start) ->where_lte('date', $end) ->order_by_desc('date') ->find_array(); // Build a new array with the data foreach ($results as $key => $value) { $data[$key]['label'] = $value['date']; $data[$key]['value'] = $value['sales_order']; } echo json_encode($data); } Here I am using a favorite library of mine - Idiorm. I have used it before in tutorials in the site (and in many personal projects). It is only one file (located in the lib/ folder) and makes working with databases a pure joy. All I am doing is selecting all the results from the database, which have a date value between the start and end timestamps passed with the request. The resulting JSON response looks similar to this: [{"label": "2013-01-07", "value": "4"}, {"label": "2013-01-06","value": "65"}, {"label": "2013-01-05","value": "96"}] The label properties contain the MySQL date values for the respective row, and the values - the number of sales for that day. It is up to our JavaScript code to correctly handle this data and turn it into a format suitable for use with the xCharts plugin. ajax-charts-jquery.jpg

    The JavaScript

    All of our JS code lies in assets/js/script.js. The code is a bit long, and to make it easier to follow I will present it to you in chunks. First we will declare a few variables and initialize the date range picker plugin. Notice that the date range I linked to is a fork of the original plugin. I decided to go with this version, as the original depends on date.js - a very old date/time library that conflicts with xCharts. The fork instead uses sugar.js which is a nice utility library with powerful date and time support.

    assets/js/script.js

    $(function() { // Set the default dates, uses sugarjs' methods var startDate = Date.create().addDays(-6), // 6 days ago endDate = Date.create(); // today var range = $('#range'); // Show the dates in the range input range.val(startDate.format('{MM}/{dd}/{yyyy}') + ' - ' + endDate.format('{MM}/{dd}/{yyyy}')); // Load chart ajaxLoadChart(startDate,endDate); range.daterangepicker({ startDate: startDate, endDate: endDate, ranges: {'Today': ['today', 'today'], 'Yesterday': ['yesterday', 'yesterday'], 'Last 7 Days': [Date.create().addDays(-6), 'today'], 'Last 30 Days': [Date.create().addDays(-29), 'today'] // You can add more entries here } },function(start, end){ ajaxLoadChart(start, end); }); As you can see, we are making good use of sugar.js' date and time methods to define the start and end point of the range. I am initializing the script with the results from the last 7 days, and updating the range input field. Now let's create the chart: // The tooltip shown over the chart var tt = $('<div class="ex-tooltip">').appendTo('body'), topOffset = -32; var data = {"xScale" : "time", "yScale" : "linear", "main" : [{className : ".stats", "data" : []}] }; var opts = { paddingLeft : 50, paddingTop : 20, paddingRight : 10, axisPaddingLeft : 25, tickHintX: 9, // How many ticks to show horizontally dataFormatX : function(x) { // This turns converts the timestamps coming from // ajax.php into a proper JavaScript Date object return Date.create(x); }, tickFormatX : function(x) { // Provide formatting for the x-axis tick labels. // This uses sugar's format method of the date object. return x.format('{MM}/{dd}'); }, "mouseover": function(d, i) { var pos = $(this).offset(); tt.text(d.x.format('{Month} {ord}') + ': ' + d.y).css({ top: topOffset + pos.top, left: pos.left }).show(); }, "mouseout": function(x) { tt.hide(); } }; // Create a new xChart instance, passing the type // of chart a data set and the options object var chart = new xChart('line-dotted', data, '#chart' , opts); First I define a configuration object for xCharts, with properties and callback functions. In the dataFormatX property, I am transforming the yyyy-mm-dd strings returned from the AJAX request, into proper JavaScript Date objects, so that the plugin can correctly display them and do its calculations. I am also passing an event handler for the mouseover/mouseout plugin events, and use them to show a tooltip (the plugin doesn't come with one out of the box). date-range-picker.jpg Lastly, here is the JavaScript function for loading data with AJAX: // Function for loading data via AJAX and showing it on the chart function ajaxLoadChart(startDate,endDate) { // If no data is passed (the chart was cleared) if(!startDate || !endDate){ chart.setData({ "xScale" : "time", "yScale" : "linear", "main" : [{ className : ".stats", data : [] }] }); return; } // Otherwise, issue an AJAX request $.getJSON('ajax.php', { start: startDate.format('{yyyy}-{MM}-{dd}'), end: endDate.format('{yyyy}-{MM}-{dd}') }, function(data) { var set = []; $.each(data, function() { set.push({ x : this.label, y : parseInt(this.value, 10) }); }); chart.setData({ "xScale" : "time", "yScale" : "linear", "main" : [{ className : ".stats", data : set }] }); }); } }); xCharts exposes the setData method so you can easily replace the displayed data. The className attribute is important, as this is what the plugin uses to identify your chart. If you omit this property, all kinds of strange bugs will occur (trust me, I know). With this our pretty charts are complete!

    We're done!

    You can use this example to enhance your admin areas and to visualize statistical data in a beautiful interface.

    jQuery Selecting Elements

    The most basic concept of jQuery is to "select some elements and do something with them." jQuery supports most CSS3 selectors, as well as some non-standard selectors. For a complete selector reference, visit the Selectors documentation on api.jquery.com.

    Selecting Elements by ID

    $( "#myId" ); // Note IDs must be unique per page.

    Selecting Elements by Class Name

    $( ".myClass" );

    Selecting Elements by Attribute

    $( "input[name='first_name']" );

    Selecting Elements by Compound CSS Selector

    $( "#contents ul.people li" );

    Selecting Elements with a Comma-separated List of Selectors

    $( "div.myClass, ul.people" );

    Pseudo-Selectors

    $( "a.external:first" ); $( "tr:odd" ); // Select all input-like elements in a form (more on this below). $( "#myForm :input" ); $( "div:visible" ); // All except the first three divs. $( "div:gt(2)" ); // All currently animated divs. $( "div:animated" ); Note: When using the :visible and :hidden pseudo-selectors, jQuery tests the actual visibility of the element, not its CSS visibility or display properties. jQuery looks to see if the element's physical height and width on the page are both greater than zero. However, this test doesn't work with <tr> elements. In the case of <tr> jQuery does check the CSS display property, and considers an element hidden if its display property is set to none. Elements that have not been added to the DOM will always be considered hidden, even if the CSS that would affect them would render them visible. See the Manipulating Elements section to learn how to create and add elements to the DOM.

    Choosing Selectors

    Choosing good selectors is one way to improve JavaScript's performance. Too much specificity can be a bad thing. A selector such as #myTable thead tr th.special is overkill if a selector such as #myTable th.special will get the job done.

    Does My Selection Contain Any Elements?

    Once you've made a selection, you'll often want to know whether you have anything to work with. A common mistake is to use: // Doesn't work! if ( $( "div.foo" ) ) { ... } This won't work. When a selection is made using $(), an object is always returned, and objects always evaluate to true. Even if the selection doesn't contain any elements, the code inside the if statement will still run. The best way to determine if there are any elements is to test the selection's .length property, which tells you how many elements were selected. If the answer is 0, the .length property will evaluate to false when used as a boolean value: // Testing whether a selection contains elements. if ( $( "div.foo" ).length ) { ... }

    Saving Selections

    jQuery doesn't cache elements for you. If you've made a selection that you might need to make again, you should save the selection in a variable rather than making the selection repeatedly. var divs = $( "div" ); Once the selection is stored in a variable, you can call jQuery methods on the variable just like you would have called them on the original selection. A selection only fetches the elements that are on the page at the time the selection is made. If elements are added to the page later, you'll have to repeat the selection or otherwise add them to the selection stored in the variable. Stored selections don't magically update when the DOM changes.

    Refining & Filtering Selections

    Sometimes the selection contains more than what you're after. jQuery offers several methods for refining and filtering selections. // Refining selections. $( "div.foo" ).has( "p" ); // div.foo elements that contain <p> tags $( "h1" ).not( ".bar" ); // h1 elements that don't have a class of bar $( "ul li" ).filter( ".current" ); // unordered list items with class of current $( "ul li" ).first(); // just the first unordered list item $( "ul li" ).eq( 5 ); // the sixth

    Selecting Form Elements

    jQuery offers several pseudo-selectors that help find elements in forms. These are especially helpful because it can be difficult to distinguish between form elements based on their state or type using standard CSS selectors.

    :checked

    Not to be confused with :checkbox, :checked targets checked checkboxes, but keep in mind that this selector works also for checked radio buttons, and <select> elements (for <select> elements only, use the :selected selector): $( "form :checked" ); The :checked pseudo-selector works when used with checkboxes, radio buttons and selects.

    :disabled

    Using the :disabled pseudo-selector targets any <input> elements with the disabled attribute: $( "form :disabled" ); In order to get the best performance using :disabled, first select elements with a standard jQuery selector, then use .filter( ":disabled" ), or precede the pseudo-selector with a tag name or some other selector.

    :enabled

    Basically the inverse of the :disabled pseudo-selector, the :enabled pseudo-selector targets any elements that do not have a disabled attribute: $( "form :enabled" ); In order to get the best performance using :enabled, first select elements with a standard jQuery selector, then use .filter( ":enabled" ), or precede the pseudo-selector with a tag name or some other selector.

    :input

    Using the :input selector selects all <input>, <textarea>, <select>, and <button> elements: $( "form :input" );

    :selected

    Using the :selected pseudo-selector targets any selected items in <option> elements: $( "form :selected" ); In order to get the best performance using :selected, first select elements with a standard jQuery selector, then use .filter( ":selected" ), or precede the pseudo-selector with a tag name or some other selector.

    Selecting by type

    jQuery provides pseudo selectors to select form-specific elements according to their type: :password :reset :radio :text :submit :checkbox :button :image :file For all of these there are side notes about performance, so be sure to check out the API docs for more in-depth information.

    Passing variable to another html page

    window.open("MusicMe.html?variable=value", "_self"); In next page, check for queryParam by getting window.location.href and using regex to split the params after ? and get that data. window.open("Charts.html?26069", "_blank"); url = window.location.href url = "asdaf ?=ddf" thecode = url.split("?=") thecode[1]

    Math.random Normal distribution

    function randn_bm() { let u = 0, v = 0; while(u === 0) u = Math.random(); //Converting [0,1) to (0,1) while(v === 0) v = Math.random(); let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v ); num = num / 10.0 + 0.5; // Translate to 0 -> 1 if (num > 1 || num < 0) return randn_bm() // resample between 0 and 1 return num } Normal Distribution With Min, Max, Skew function randn_bm(min, max, skew) { let u = 0, v = 0; while(u === 0) u = Math.random() //Converting [0,1) to (0,1) while(v === 0) v = Math.random() let num = Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v ) num = num / 10.0 + 0.5 // Translate to 0 -> 1 if (num > 1 || num < 0) num = randn_bm(min, max, skew) // resample between 0 and 1 if out of range else{ num = Math.pow(num, skew) // Skew num *= max - min // Stretch to fill range num += min // offset to min } return num } randn_bm(-500, 1000, 1); randn_bm(10, 20, 0.25); randn_bm(10, 20, 3);

    create heatmap

    <script src='https://cdn.plot.ly/plotly-2.34.0.min.js'></script> <div id='myDiv'></div> <script> var data = [ { z: [[1, 20, 50, 30], [20, 1, 50, 60], [30, 50, 60, 1], [20, 50, 40, 1]], type: 'heatmap' } ]; Plotly.newPlot('myDiv', data); </script>

    Create an Array of Numbers

    arrayLike = {0: 5, 1: 2, 2: 3, length: 3}; newArray = Array.from(arrayLike); console.log(newArray); // [1,2,3] newArray = Array.from("freeCodeCamp"); console.log(newArray); // ["f","r","e","e","C","o","d","e","C","a","m","p"] arrayLike = {0: 1, 1: 2, 2: 3, length: 3}; let newArray = Array.from(arrayLike, x => x * 2); console.log(newArray); // [2,4,6] newArray = Array.from({ length: 7 }, (value, index) => index); console.log(newArray); // [0,1,2,3,4,5,6] arrayRange = (start, stop, step) => Array.from( { length: (stop - start) / step + 1 }, (value, index) => start + index * step ); // Generate numbers between range 2 and 7 let range = arrayRange(2, 7, 1); console.log(range); // [2,3,4,5,6,7] // Generate even numbers between range 2 and 7 let evenRange = arrayRange(2, 7, 2); console.log(evenRange); // [2,4,6] // Generate odd numbers between range 1 and 5 let oddRange = arrayRange(1, 5, 2); console.log(oddRange); // [1,3,5]

    Heatmap by AnyChart JS library

    Heatmap sample plotly heatmaps <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-core.min.js"></script> <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-heatmap.min.js"></script> <div id="container"></div> <script> anychart.onDocumentReady(function() { // create a heatmap let chart = anychart.heatMap(getData()); // name the heatmap chart.title("Fatal Car Crashes 2021 by Time of Day and Day of Week"); // set the container for the heatmap chart.container("container"); // draw the heatmap chart.draw(); }); function getData() { return [ { x: "Monday", y: "Midnight–3:59 a.m.", heat: 705}, { x: "Monday", y: "4:00–7:59 a.m.", heat: 713}, { x: "Monday", y: "8:00–11:59 a.m.", heat: 657}, { x: "Monday", y: "Noon–3:59 p.m.", heat: 957}, { x: "Monday", y: "4:00–7:59 p.m.", heat: 1137}, { x: "Monday", y: "8:00–11:59 p.m.", heat: 956}, { x: "Tuesday", y: "Midnight–3:59 a.m.", heat: 482}, { x: "Tuesday", y: "4:00–7:59 a.m.", heat: 641}, { x: "Tuesday", y: "8:00–11:59 a.m.", heat: 631}, { x: "Tuesday", y: "Noon–3:59 p.m.", heat: 905}, { x: "Tuesday", y: "4:00–7:59 p.m.", heat: 1137}, { x: "Tuesday", y: "8:00–11:59 p.m.", heat: 986}, { x: "Wednesday", y: "Midnight–3:59 a.m.", heat: 465}, { x: "Wednesday", y: "4:00–7:59 a.m.", heat: 616}, { x: "Wednesday", y: "8:00–11:59 a.m.", heat: 627}, { x: "Wednesday", y: "Noon–3:59 p.m.", heat: 914}, { x: "Wednesday", y: "4:00–7:59 p.m.", heat: 1159}, { x: "Wednesday", y: "8:00–11:59 p.m.", heat: 1066}, { x: "Thursday", y: "Midnight–3:59 a.m.", heat: 584}, { x: "Thursday", y: "4:00–7:59 a.m.", heat: 718}, { x: "Thursday", y: "8:00–11:59 a.m.", heat: 660}, { x: "Thursday", y: "Noon–3:59 p.m.", heat: 966}, { x: "Thursday", y: "4:00–7:59 p.m.", heat: 1161}, { x: "Thursday", y: "8:00–11:59 p.m.", heat: 1186}, { x: "Friday", y: "Midnight–3:59 a.m.", heat: 715}, { x: "Friday", y: "4:00–7:59 a.m.", heat: 747}, { x: "Friday", y: "8:00–11:59 a.m.", heat: 738}, { x: "Friday", y: "Noon–3:59 p.m.", heat: 1056}, { x: "Friday", y: "4:00–7:59 p.m.", heat: 1426}, { x: "Friday", y: "8:00–11:59 p.m.", heat: 1631}, { x: "Saturday", y: "Midnight–3:59 a.m.", heat: 1383}, { x: "Saturday", y: "4:00–7:59 a.m.", heat: 641}, { x: "Saturday", y: "8:00–11:59 a.m.", heat: 635}, { x: "Saturday", y: "Noon–3:59 p.m.", heat: 1034}, { x: "Saturday", y: "4:00–7:59 p.m.", heat: 1400}, { x: "Saturday", y: "8:00–11:59 p.m.", heat: 1593}, { x: "Sunday", y: "Midnight–3:59 a.m.", heat: 1486}, { x: "Sunday", y: "4:00–7:59 a.m.", heat: 695}, { x: "Sunday", y: "8:00–11:59 a.m.", heat: 564}, { x: "Sunday", y: "Noon–3:59 p.m.", heat: 932}, { x: "Sunday", y: "4:00–7:59 p.m.", heat: 1292}, { x: "Sunday", y: "8:00–11:59 p.m.", heat: 1211} ]; } </script> //Change the Color Palette let colorScale = anychart.scales.ordinalColor(); colorScale.ranges([ { less: 500, color: "#B0D8A4" }, { from: 500, to: 900, color: "#FEE191" }, { from: 900, to: 1300, color: "#FD8060" }, { greater: 1300, color: "#CC333F" } ]); chart.colorScale(colorScale); //Modify the Hover Styling chart .hovered() .fill(function() { return anychart.color.darken(this.sourceColor, 0.25); }); //Change the Labels // enable html for the labels chart.labels().useHtml(true); // configure the labels chart.labels().format(function() { var heat = this.heat; if (heat < 500) return "Low"; if (heat < 1000) return "Medium"; if (heat < 1500) return "<span style='font-weight:bold'>High</span>"; if (heat >= 1500) return "<span style='font-weight:bold'>Extreme</span>"; }); //Format the Title and Tooltip chart.tooltip().title().useHtml(true); chart .tooltip() .useHtml(true) .titleFormat(function() { return "Accidents - " + this.heat; }) .format(function() { return ( '<span style="color: #CECECE">Day: </span>' + this.x + "<br/>" + '<span style="color: #CECECE">Time: </span>' + this.y ); }); //add a bit of padding under the main title to make it more spaced out and visually appealing: chart .title() .enabled(true) .text("Fatal Car Crashes in U.S. in 2021 by Time of Day and Day of Week") .padding([0, 0, 20, 0]); Modify the Axes chart.xAxis().stroke(null); chart.yAxis().stroke(null); chart.yAxis().labels().padding([0, 10, 0, 0]); chart.xAxis().labels().padding([0, 0, 10, 0]);

    normalizeCode

    function normalizeCode(theCode) { if( theCode.substring(0, 2) == "us"){ theurl = 'https://web.ifzq.gtimg.cn/appstock/app/usfqkline/get?_var=kline_dayqfq¶m=' + theCode + ',day,,,1000,qfq'; imageCode = theCode }else{ if(theCode == "110000"){ theCode = "HSI"; imageCode = "110000" } codewidth = theCode.length if(theCode == "HSI"){ theurl = 'https://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?_var=kline_dayqfq¶m=hk' + theCode + ',day,,,1000,qfq'; imageCode = "110000" }else{ if(codewidth <= 5){ theCode = "00000"+theCode; codewidth = theCode.length; theCode = theCode.slice(codewidth-5, codewidth); codewidth = theCode.length; //update to be used later theStartCode = theCode imageCode = theCode theurl = 'https://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?_var=kline_dayqfq¶m=hk' + theCode + ',day,,,1000,qfq'; }else{ codewidth = theCode.length if((codewidth == 6) && !hsReservedCode.includes(theCode)){ if (theCode.charAt(0) == "6"){ imageCode = theCode+".sh"; // note this comes before following line theCode = "sh"+theCode; }else{ imageCode = theCode+".sz"; theCode = "sz"+theCode } theStartCode = theCode theurl = 'https://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq¶m=' + theCode + ',day,,,1000,qfq'; }else if(codewidth == 9){ imageCode = theCode theCode = theCode.substring(7, 9) + theCode.substring(0, 6); theStartCode = theCode theurl = 'https://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq¶m=' + theCode + ',day,,,1000,qfq'; }else{ theurl = 'https://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq¶m=' + theCode + ',day,,,1000,qfq'; theStartCode = theCode imageCode = theCode } } } } }

    grab data from external JSON

    look at xmlHttpRequests or an equivalent. e.g. var xmlhttp = new XMLHttpRequest(); <div id="demo"></div> <script> const xmlhttp = new XMLHttpRequest(); theCode = 388 theCode = "00000"+theCode; codewidth = theCode.length; theCode = theCode.slice(codewidth-5, codewidth); codewidth = theCode.length; //update to be used later theStartCode = theCode imageCode = theCode theurl = 'https://web.ifzq.gtimg.cn/appstock/app/hkfqkline/get?_var=kline_dayqfq¶m=hk' + theCode + ',day,,,1000,qfq'; // Define a callback function xmlhttp.onload = function() { // this.responseText is a string document.getElementById("demo").innerHTML = this.responseText; // JSON.stringify; convert string to json var jsonData = JSON.stringify(this.responseText); // document.getElementById("json").innerHTML = jsonData; // eval(this.responseText); another way to convert string to json myObj = eval(this.responseText) // document.getElementById("json").innerHTML = myObj; console.log(Object.keys(myObj)) // show the keys console.log(kline_dayqfq) // kline_dayqfq is name of object console.log(Object.keys(kline_dayqfq.data)) // show the keys console.log(kline_dayqfq.data["hk00388"]) } // Send a request xmlhttp.open("GET", theurl); xmlhttp.send(); let trace1 = { x: [], y: [], mode: "lines" }; let trace2 = { x: [], y: [], mode: "lines" }; data.forEach(function(val) { trace1.x.push(val["time"]); trace1.y.push(val["pm25"]); trace2.x.push(val["time"]); trace2.y.push(val["pm10"]); }); Plotly.newPlot('AQI', [trace1, trace2]); </script>

    Convert String to JSON Using json.stringify()

    The basic syntax: JSON.stringify(source_of_data) let jsonData = JSON.stringify(source_of_data); console.log(jsonData);

    Convert String to JSON Using eval()

    The eval() function in JavaScript is used to take an expression and return the string. As a result, it can be used to convert the string into JSON. The string or an expression can be the value of eval(), and even if you pass multiple statements as an expression, the result will still work. The simple syntax for using eval() is as follows: eval(string_value)

    Using a loop to create objects

    var title = []; for (var i=0; i<3; i++) { title[i] = { name: "name" + i+1, age: "age" + i+1, hometown: "hometown" + i+1 }; } console.log(title); // output will be: // [ { name: 'name1', age: 'age1', hometown: 'hometown1' }, // { name: 'name2', age: 'age2', hometown: 'hometown2' }, // { name: 'name3', age: 'age3', hometown: 'hometown3' }]

    Plotly Figure Reference: layout


    all layout childs
    title
     automargin
     font
      color
      family
      lineposition
      shadow
      size
      style
      textcase
      variant
      weight
     pad
      b
      l
      r
      t
     subtitle
      font
       color
       family
       lineposition
       shadow
       size
       style
       textcase
       variant
       weight
      text
     text
     x
     xanchor
     xref
     y
     yanchor
     yref
    showlegend
    legend
     bgcolor
     bordercolor
     borderwidth
     entrywidth
     entrywidthmode
     font
      color
      family
      lineposition
      shadow
      size
      style
      textcase
      variant
      weight
     groupclick
     grouptitlefont
      color
      family
      lineposition
      shadow
      size
      style
      textcase
      variant
      weight
     indentation
     itemclick
     itemdoubleclick
     itemsizing
     itemwidth
     orientation
     title
      font
       color
       family
       lineposition
       shadow
       size
       style
       textcase
       variant
       weight
      side
      text
     tracegroupgap
     traceorder
     uirevision
     valign
     visible
     x
     xanchor
     xref
     y
     yanchor
     yref
    margin
     autoexpand
     b
     l
     pad
     r
     t
    autosize
    width
    height
    font
     color
     family
     lineposition
     shadow
     size
     style
     textcase
     variant
     weight
    uniformtext
     minsize
     mode
    separators
    paper_bgcolor
    plot_bgcolor
    autotypenumbers
    colorscale
     diverging
     sequential
     sequentialminus
    colorway
    modebar
     activecolor
     add
     bgcolor
     color
     orientation
     remove
     uirevision
    hovermode
    hoversubplots
    clickmode
    dragmode
    selectdirection
    activeselection
     fillcolor
     opacity
    newselection
     line
      color
      dash
      width
     mode
    hoverdistance
    spikedistance
    hoverlabel
     align
     bgcolor
     bordercolor
     font
      color
      family
      lineposition
      shadow
      size
      style
      textcase
      variant
      weight
     grouptitlefont
      color
      family
      lineposition
      shadow
      size
      style
      textcase
      variant
      weight
     namelength
    transition
     duration
     easing
     ordering
    datarevision
    uirevision
    editrevision
    selectionrevision
    template
    meta
    computed
    grid
     columns
     domain
      x
      y
     pattern
     roworder
     rows
     subplots
     xaxes
     xgap
     xside
     yaxes
     ygap
     yside
    calendar
    minreducedheight
    minreducedwidth
    newshape
     drawdirection
     fillcolor
     fillrule
     label
      font
       color
       family
       lineposition
       shadow
       size
       style
       textcase
       variant
       weight
      text
      textangle
      textposition
      texttemplate
      xanchor
      yanchor
     layer
     legend
     legendgroup
     legendgrouptitle
      font
       color
       family
       lineposition
       shadow
       size
       style
       textcase
       variant
       weight
      text
     legendrank
     legendwidth
     line
      color
      dash
      width
     name
     opacity
     showlegend
     visible
    activeshape
     fillcolor
     opacity
    selections
     line
      color
      dash
      width
     name
     opacity
     path
     templateitemname
     type
     x0
     x1
     xref
     y0
     y1
     yref
    hidesources
    scattergap
    scattermode
    barcornerradius
    extendpiecolors
    hiddenlabels
    piecolorway
    violingap
    violingroupgap
    violinmode
    bargroupgap
    barmode
    barnorm
    boxgap
    boxgroupgap
    boxmode
    waterfallgap
    waterfallgroupgap
    waterfallmode
    funnelgap
    funnelgroupgap
    funnelmode
    extendfunnelareacolors
    funnelareacolorway
    bargap
    extendsunburstcolors
    sunburstcolorway
    extendtreemapcolors
    treemapcolorway
    extendiciclecolors
    iciclecolorway

    all layout childs

    activeselection, activeshape, autosize, autotypenumbers, barcornerradius, bargap, bargroupgap, barmode, barnorm, boxgap, boxgroupgap, boxmode, calendar, clickmode, colorscale, colorway, computed, datarevision, dragmode, editrevision, extendfunnelareacolors, extendiciclecolors, extendpiecolors, extendsunburstcolors, extendtreemapcolors, font, funnelareacolorway, funnelgap, funnelgroupgap, funnelmode, grid, height, hiddenlabels, hidesources, hoverdistance, hoverlabel, hovermode, hoversubplots, iciclecolorway, legend, margin, meta, minreducedheight, minreducedwidth, modebar, newselection, newshape, paper_bgcolor, piecolorway, plot_bgcolor, scattergap, scattermode, selectdirection, selectionrevision, selections, separators, showlegend, spikedistance, sunburstcolorway, template, title, transition, treemapcolorway, uirevision, uniformtext, violingap, violingroupgap, violinmode, waterfallgap, waterfallgroupgap, waterfallmode, width

    title

    Parent: layout Type: object containing one or more of the keys listed below.

     automargin

    Parent: layout.title Type: boolean Determines whether the title can automatically push the figure margins. If `yref='paper'` then the margin will expand to ensure that the title doesn’t overlap with the edges of the container. If `yref='container'` then the margins will ensure that the title doesn’t overlap with the plot area, tick labels, and axis titles. If `automargin=true` and the margins need to be expanded, then y will be set to a default 1 and yanchor will be set to an appropriate default to ensure that minimal margin space is needed. Note that when `yref='paper'`, only 1 or 0 are allowed y values. Invalid values will be reset to the default 1.

     font

    Parent: layout.title Type: object containing one or more of the keys listed below. Sets the title font. Note that the title's font used to be customized by the now deprecated `titlefont` attribute.

      color

    Parent: layout.title.font Type: color

      family

    Parent: layout.title.font Type: string HTML font family - the typeface that will be applied by the web browser. The web browser will only be able to apply a font if it is available on the system which it operates. Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts if they aren't available on the system. The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server, where only a select number of fonts are installed and supported. These include "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman".

      lineposition

    Parent: layout.title.font Type: flaglist string. Any combination of "under", "over", "through" joined with a "+" OR "none". Examples: "under", "over", "under+over", "under+over+through", "none" Default: "none" Sets the kind of decoration line(s) with text, such as an "under", "over" or "through" as well as combinations e.g. "under+over", etc.

      shadow

    Parent: layout.title.font Type: string Default: "none" Sets the shape and color of the shadow behind text. "auto" places minimal shadow and applies contrast text font color. See https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow for additional options.

      size

    Parent: layout.title.font Type: number greater than or equal to 1

      style

    Parent: layout.title.font Type: enumerated , one of ( "normal" | "italic" ) Default: "normal" Sets whether a font should be styled with a normal or italic face from its family.

      textcase

    Parent: layout.title.font Type: enumerated , one of ( "normal" | "word caps" | "upper" | "lower" ) Default: "normal" Sets capitalization of text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

      variant

    Parent: layout.title.font Type: enumerated , one of ( "normal" | "small-caps" | "all-small-caps" | "all-petite-caps" | "petite-caps" | "unicase" ) Default: "normal" Sets the variant of the font.

      weight

    Parent: layout.title.font Type: integer between or equal to 1 and 1000 Default: normal Sets the weight (or boldness) of the font.

     pad

    Parent: layout.title Type: object containing one or more of the keys listed below. Sets the padding of the title. Each padding value only applies when the corresponding `xanchor`/`yanchor` value is set accordingly. E.g. for left padding to take effect, `xanchor` must be set to "left". The same rule applies if `xanchor`/`yanchor` is determined automatically. Padding is muted if the respective anchor value is "middle"/"center".

      b

    Parent: layout.title.pad Type: number Default: 0 The amount of padding (in px) along the bottom of the component.

      l

    Parent: layout.title.pad Type: number Default: 0 The amount of padding (in px) on the left side of the component.

      r

    Parent: layout.title.pad Type: number Default: 0 The amount of padding (in px) on the right side of the component.

      t

    Parent: layout.title.pad Type: number Default: 0 The amount of padding (in px) along the top of the component.

     subtitle

    Parent: layout.title Type: object containing one or more of the keys listed below.

      font

    Parent: layout.title.subtitle Type: object containing one or more of the keys listed below. Sets the subtitle font.

       color

    Parent: layout.title.subtitle.font Type: color

       family

    Parent: layout.title.subtitle.font Type: string HTML font family - the typeface that will be applied by the web browser. The web browser will only be able to apply a font if it is available on the system which it operates. Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts if they aren't available on the system. The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server, where only a select number of fonts are installed and supported. These include "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman".

       lineposition

    Parent: layout.title.subtitle.font Type: flaglist string. Any combination of "under", "over", "through" joined with a "+" OR "none". Examples: "under", "over", "under+over", "under+over+through", "none" Default: "none" Sets the kind of decoration line(s) with text, such as an "under", "over" or "through" as well as combinations e.g. "under+over", etc.

       shadow

    Parent: layout.title.subtitle.font Type: string Default: "none" Sets the shape and color of the shadow behind text. "auto" places minimal shadow and applies contrast text font color. See https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow for additional options.

       size

    Parent: layout.title.subtitle.font Type: number greater than or equal to 1

       style

    Parent: layout.title.subtitle.font Type: enumerated , one of ( "normal" | "italic" ) Default: "normal" Sets whether a font should be styled with a normal or italic face from its family.

       textcase

    Parent: layout.title.subtitle.font Type: enumerated , one of ( "normal" | "word caps" | "upper" | "lower" ) Default: "normal" Sets capitalization of text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

       variant

    Parent: layout.title.subtitle.font Type: enumerated , one of ( "normal" | "small-caps" | "all-small-caps" | "all-petite-caps" | "petite-caps" | "unicase" ) Default: "normal" Sets the variant of the font.

       weight

    Parent: layout.title.subtitle.font Type: integer between or equal to 1 and 1000 Default: normal Sets the weight (or boldness) of the font.

      text

    Parent: layout.title.subtitle Type: string Sets the plot's subtitle.

     text

    Parent: layout.title Type: string Sets the plot's title. Note that before the existence of `title.text`, the title's contents used to be defined as the `title` attribute itself. This behavior has been deprecated.

     x

    Parent: layout.title Type: number between or equal to 0 and 1 Default: 0.5 Sets the x position with respect to `xref` in normalized coordinates from "0" (left) to "1" (right).

     xanchor

    Parent: layout.title Type: enumerated , one of ( "auto" | "left" | "center" | "right" ) Default: "auto" Sets the title's horizontal alignment with respect to its x position. "left" means that the title starts at x, "right" means that the title ends at x and "center" means that the title's center is at x. "auto" divides `xref` by three and calculates the `xanchor` value automatically based on the value of `x`.

     xref

    Parent: layout.title Type: enumerated , one of ( "container" | "paper" ) Default: "container" Sets the container `x` refers to. "container" spans the entire `width` of the plot. "paper" refers to the width of the plotting area only.

     y

    Parent: layout.title Type: number between or equal to 0 and 1 Default: "auto" Sets the y position with respect to `yref` in normalized coordinates from "0" (bottom) to "1" (top). "auto" places the baseline of the title onto the vertical center of the top margin.

     yanchor

    Parent: layout.title Type: enumerated , one of ( "auto" | "top" | "middle" | "bottom" ) Default: "auto" Sets the title's vertical alignment with respect to its y position. "top" means that the title's cap line is at y, "bottom" means that the title's baseline is at y and "middle" means that the title's midline is at y. "auto" divides `yref` by three and calculates the `yanchor` value automatically based on the value of `y`.

     yref

    Parent: layout.title Type: enumerated , one of ( "container" | "paper" ) Default: "container" Sets the container `y` refers to. "container" spans the entire `height` of the plot. "paper" refers to the height of the plotting area only.

    showlegend

    Parent: layout Type: boolean Determines whether or not a legend is drawn. Default is `true` if there is a trace to show and any of these: a) Two or more traces would by default be shown in the legend. b) One pie trace is shown in the legend. c) One trace is explicitly given with `showlegend: true`.

    legend

    Parent: layout Type: object containing one or more of the keys listed below.

     bgcolor

    Parent: layout.legend Type: color Sets the legend background color. Defaults to `layout.paper_bgcolor`.

     bordercolor

    Parent: layout.legend Type: color Default: "#444" Sets the color of the border enclosing the legend.

     borderwidth

    Parent: layout.legend Type: number greater than or equal to 0 Default: 0 Sets the width (in px) of the border enclosing the legend.

     entrywidth

    Parent: layout.legend Type: number greater than or equal to 0 Sets the width (in px or fraction) of the legend. Use 0 to size the entry based on the text width, when `entrywidthmode` is set to "pixels".

     entrywidthmode

    Parent: layout.legend Type: enumerated , one of ( "fraction" | "pixels" ) Default: "pixels" Determines what entrywidth means.

     font

    Parent: layout.legend Type: object containing one or more of the keys listed below. Sets the font used to text the legend items.

      color

    Parent: layout.legend.font Type: color

      family

    Parent: layout.legend.font Type: string HTML font family - the typeface that will be applied by the web browser. The web browser will only be able to apply a font if it is available on the system which it operates. Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts if they aren't available on the system. The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server, where only a select number of fonts are installed and supported. These include "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman".

      lineposition

    Parent: layout.legend.font Type: flaglist string. Any combination of "under", "over", "through" joined with a "+" OR "none". Examples: "under", "over", "under+over", "under+over+through", "none" Default: "none" Sets the kind of decoration line(s) with text, such as an "under", "over" or "through" as well as combinations e.g. "under+over", etc.

      shadow

    Parent: layout.legend.font Type: string Default: "none" Sets the shape and color of the shadow behind text. "auto" places minimal shadow and applies contrast text font color. See https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow for additional options.

      size

    Parent: layout.legend.font Type: number greater than or equal to 1

      style

    Parent: layout.legend.font Type: enumerated , one of ( "normal" | "italic" ) Default: "normal" Sets whether a font should be styled with a normal or italic face from its family.

      textcase

    Parent: layout.legend.font Type: enumerated , one of ( "normal" | "word caps" | "upper" | "lower" ) Default: "normal" Sets capitalization of text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

      variant

    Parent: layout.legend.font Type: enumerated , one of ( "normal" | "small-caps" | "all-small-caps" | "all-petite-caps" | "petite-caps" | "unicase" ) Default: "normal" Sets the variant of the font.

      weight

    Parent: layout.legend.font Type: integer between or equal to 1 and 1000 Default: normal Sets the weight (or boldness) of the font.

     groupclick

    Parent: layout.legend Type: enumerated , one of ( "toggleitem" | "togglegroup" ) Default: "togglegroup" Determines the behavior on legend group item click. "toggleitem" toggles the visibility of the individual item clicked on the graph. "togglegroup" toggles the visibility of all items in the same legendgroup as the item clicked on the graph.

     grouptitlefont

    Parent: layout.legend Type: object containing one or more of the keys listed below. Sets the font for group titles in legend. Defaults to `legend.font` with its size increased about 10%.

      color

    Parent: layout.legend.grouptitlefont Type: color

      family

    Parent: layout.legend.grouptitlefont Type: string HTML font family - the typeface that will be applied by the web browser. The web browser will only be able to apply a font if it is available on the system which it operates. Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts if they aren't available on the system. The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server, where only a select number of fonts are installed and supported. These include "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman".

      lineposition

    Parent: layout.legend.grouptitlefont Type: flaglist string. Any combination of "under", "over", "through" joined with a "+" OR "none". Examples: "under", "over", "under+over", "under+over+through", "none" Default: "none" Sets the kind of decoration line(s) with text, such as an "under", "over" or "through" as well as combinations e.g. "under+over", etc.

      shadow

    Parent: layout.legend.grouptitlefont Type: string Default: "none" Sets the shape and color of the shadow behind text. "auto" places minimal shadow and applies contrast text font color. See https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow for additional options.

      size

    Parent: layout.legend.grouptitlefont Type: number greater than or equal to 1

      style

    Parent: layout.legend.grouptitlefont Type: enumerated , one of ( "normal" | "italic" ) Default: "normal" Sets whether a font should be styled with a normal or italic face from its family.

      textcase

    Parent: layout.legend.grouptitlefont Type: enumerated , one of ( "normal" | "word caps" | "upper" | "lower" ) Default: "normal" Sets capitalization of text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

      variant

    Parent: layout.legend.grouptitlefont Type: enumerated , one of ( "normal" | "small-caps" | "all-small-caps" | "all-petite-caps" | "petite-caps" | "unicase" ) Default: "normal" Sets the variant of the font.

      weight

    Parent: layout.legend.grouptitlefont Type: integer between or equal to 1 and 1000 Default: normal Sets the weight (or boldness) of the font.

     indentation

    Parent: layout.legend Type: number greater than or equal to -15 Default: 0 Sets the indentation (in px) of the legend entries.

     itemclick

    Parent: layout.legend Type: enumerated , one of ( "toggle" | "toggleothers" | false ) Default: "toggle" Determines the behavior on legend item click. "toggle" toggles the visibility of the item clicked on the graph. "toggleothers" makes the clicked item the sole visible item on the graph. "false" disables legend item click interactions.

     itemdoubleclick

    Parent: layout.legend Type: enumerated , one of ( "toggle" | "toggleothers" | false ) Default: "toggleothers" Determines the behavior on legend item double-click. "toggle" toggles the visibility of the item clicked on the graph. "toggleothers" makes the clicked item the sole visible item on the graph. "false" disables legend item double-click interactions.

     itemsizing

    Parent: layout.legend Type: enumerated , one of ( "trace" | "constant" ) Default: "trace" Determines if the legend items symbols scale with their corresponding "trace" attributes or remain "constant" independent of the symbol size on the graph.

     itemwidth

    Parent: layout.legend Type: number greater than or equal to 30 Default: 30 Sets the width (in px) of the legend item symbols (the part other than the title.text).

     orientation

    Parent: layout.legend Type: enumerated , one of ( "v" | "h" ) Default: "v" Sets the orientation of the legend.

     title

    Parent: layout.legend Type: object containing one or more of the keys listed below.

      font

    Parent: layout.legend.title Type: object containing one or more of the keys listed below. Sets this legend's title font. Defaults to `legend.font` with its size increased about 20%.

       color

    Parent: layout.legend.title.font Type: color

       family

    Parent: layout.legend.title.font Type: string HTML font family - the typeface that will be applied by the web browser. The web browser will only be able to apply a font if it is available on the system which it operates. Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts if they aren't available on the system. The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server, where only a select number of fonts are installed and supported. These include "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman".

       lineposition

    Parent: layout.legend.title.font Type: flaglist string. Any combination of "under", "over", "through" joined with a "+" OR "none". Examples: "under", "over", "under+over", "under+over+through", "none" Default: "none" Sets the kind of decoration line(s) with text, such as an "under", "over" or "through" as well as combinations e.g. "under+over", etc.

       shadow

    Parent: layout.legend.title.font Type: string Default: "none" Sets the shape and color of the shadow behind text. "auto" places minimal shadow and applies contrast text font color. See https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow for additional options.

       size

    Parent: layout.legend.title.font Type: number greater than or equal to 1

       style

    Parent: layout.legend.title.font Type: enumerated , one of ( "normal" | "italic" ) Default: "normal" Sets whether a font should be styled with a normal or italic face from its family.

       textcase

    Parent: layout.legend.title.font Type: enumerated , one of ( "normal" | "word caps" | "upper" | "lower" ) Default: "normal" Sets capitalization of text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

       variant

    Parent: layout.legend.title.font Type: enumerated , one of ( "normal" | "small-caps" | "all-small-caps" | "all-petite-caps" | "petite-caps" | "unicase" ) Default: "normal" Sets the variant of the font.

       weight

    Parent: layout.legend.title.font Type: integer between or equal to 1 and 1000 Default: normal Sets the weight (or boldness) of the font.

      side

    Parent: layout.legend.title Type: enumerated , one of ( "top" | "left" | "top left" | "top center" | "top right" ) Determines the location of legend's title with respect to the legend items. Defaulted to "top" with `orientation` is "h". Defaulted to "left" with `orientation` is "v". The "top left" options could be used to expand top center and top right are for horizontal alignment legend area in both x and y sides.

      text

    Parent: layout.legend.title Type: string Default: "" Sets the title of the legend.

     tracegroupgap

    Parent: layout.legend Type: number greater than or equal to 0 Default: 10 Sets the amount of vertical space (in px) between legend groups.

     traceorder

    Parent: layout.legend Type: flaglist string. Any combination of "reversed", "grouped" joined with a "+" OR "normal". Examples: "reversed", "grouped", "reversed+grouped", "normal" Determines the order at which the legend items are displayed. If "normal", the items are displayed top-to-bottom in the same order as the input data. If "reversed", the items are displayed in the opposite order as "normal". If "grouped", the items are displayed in groups (when a trace `legendgroup` is provided). if "grouped+reversed", the items are displayed in the opposite order as "grouped".

     uirevision

    Parent: layout.legend Type: number or categorical coordinate string Controls persistence of legend-driven changes in trace and pie label visibility. Defaults to `layout.uirevision`.

     valign

    Parent: layout.legend Type: enumerated , one of ( "top" | "middle" | "bottom" ) Default: "middle" Sets the vertical alignment of the symbols with respect to their associated text.

     visible

    Parent: layout.legend Type: boolean Default: true Determines whether or not this legend is visible.

     x

    Parent: layout.legend Type: number Sets the x position with respect to `xref` (in normalized coordinates) of the legend. When `xref` is "paper", defaults to "1.02" for vertical legends and defaults to "0" for horizontal legends. When `xref` is "container", defaults to "1" for vertical legends and defaults to "0" for horizontal legends. Must be between "0" and "1" if `xref` is "container". and between "-2" and "3" if `xref` is "paper".

     xanchor

    Parent: layout.legend Type: enumerated , one of ( "auto" | "left" | "center" | "right" ) Default: "left" Sets the legend's horizontal position anchor. This anchor binds the `x` position to the "left", "center" or "right" of the legend. Value "auto" anchors legends to the right for `x` values greater than or equal to 2/3, anchors legends to the left for `x` values less than or equal to 1/3 and anchors legends with respect to their center otherwise.

     xref

    Parent: layout.legend Type: enumerated , one of ( "container" | "paper" ) Default: "paper" Sets the container `x` refers to. "container" spans the entire `width` of the plot. "paper" refers to the width of the plotting area only.

     y

    Parent: layout.legend Type: number Sets the y position with respect to `yref` (in normalized coordinates) of the legend. When `yref` is "paper", defaults to "1" for vertical legends, defaults to "-0.1" for horizontal legends on graphs w/o range sliders and defaults to "1.1" for horizontal legends on graph with one or multiple range sliders. When `yref` is "container", defaults to "1". Must be between "0" and "1" if `yref` is "container" and between "-2" and "3" if `yref` is "paper".

     yanchor

    Parent: layout.legend Type: enumerated , one of ( "auto" | "top" | "middle" | "bottom" ) Sets the legend's vertical position anchor This anchor binds the `y` position to the "top", "middle" or "bottom" of the legend. Value "auto" anchors legends at their bottom for `y` values less than or equal to 1/3, anchors legends to at their top for `y` values greater than or equal to 2/3 and anchors legends with respect to their middle otherwise.

     yref

    Parent: layout.legend Type: enumerated , one of ( "container" | "paper" ) Default: "paper" Sets the container `y` refers to. "container" spans the entire `height` of the plot. "paper" refers to the height of the plotting area only.

    margin

    Parent: layout Type: object containing one or more of the keys listed below.

     autoexpand

    Parent: layout.margin Type: boolean Default: true Turns on/off margin expansion computations. Legends, colorbars, updatemenus, sliders, axis rangeselector and rangeslider are allowed to push the margins by defaults.

     b

    Parent: layout.margin Type: number greater than or equal to 0 Default: 80 Sets the bottom margin (in px).

     l

    Parent: layout.margin Type: number greater than or equal to 0 Default: 80 Sets the left margin (in px).

     pad

    Parent: layout.margin Type: number greater than or equal to 0 Default: 0 Sets the amount of padding (in px) between the plotting area and the axis lines

     r

    Parent: layout.margin Type: number greater than or equal to 0 Default: 80 Sets the right margin (in px).

     t

    Parent: layout.margin Type: number greater than or equal to 0 Default: 100 Sets the top margin (in px).

    autosize

    Parent: layout Type: boolean Determines whether or not a layout width or height that has been left undefined by the user is initialized on each relayout. Note that, regardless of this attribute, an undefined layout width or height is always initialized on the first call to plot.

    width

    Parent: layout Type: number greater than or equal to 10 Default: 700 Sets the plot's width (in px).

    height

    Parent: layout Type: number greater than or equal to 10 Default: 450 Sets the plot's height (in px).

    font

    Parent: layout Type: object containing one or more of the keys listed below. Sets the global font. Note that fonts used in traces and other layout components inherit from the global font.

     color

    Parent: layout.font Type: color Default: "#444"

     family

    Parent: layout.font Type: string Default: ""Open Sans", verdana, arial, sans-serif" HTML font family - the typeface that will be applied by the web browser. The web browser will only be able to apply a font if it is available on the system which it operates. Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts if they aren't available on the system. The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server, where only a select number of fonts are installed and supported. These include "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman".

     lineposition

    Parent: layout.font Type: flaglist string. Any combination of "under", "over", "through" joined with a "+" OR "none". Examples: "under", "over", "under+over", "under+over+through", "none" Default: "none" Sets the kind of decoration line(s) with text, such as an "under", "over" or "through" as well as combinations e.g. "under+over", etc.

     shadow

    Parent: layout.font Type: string Default: "none" Sets the shape and color of the shadow behind text. "auto" places minimal shadow and applies contrast text font color. See https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow for additional options.

     size

    Parent: layout.font Type: number greater than or equal to 1 Default: 12

     style

    Parent: layout.font Type: enumerated , one of ( "normal" | "italic" ) Default: "normal" Sets whether a font should be styled with a normal or italic face from its family.

     textcase

    Parent: layout.font Type: enumerated , one of ( "normal" | "word caps" | "upper" | "lower" ) Default: "normal" Sets capitalization of text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

     variant

    Parent: layout.font Type: enumerated , one of ( "normal" | "small-caps" | "all-small-caps" | "all-petite-caps" | "petite-caps" | "unicase" ) Default: "normal" Sets the variant of the font.

     weight

    Parent: layout.font Type: integer between or equal to 1 and 1000 Default: normal Sets the weight (or boldness) of the font.

    uniformtext

    Parent: layout Type: object containing one or more of the keys listed below.

     minsize

    Parent: layout.uniformtext Type: number greater than or equal to 0 Default: 0 Sets the minimum text size between traces of the same type.

     mode

    Parent: layout.uniformtext Type: enumerated , one of ( false | "hide" | "show" ) Determines how the font size for various text elements are uniformed between each trace type. If the computed text sizes were smaller than the minimum size defined by `uniformtext.minsize` using "hide" option hides the text; and using "show" option shows the text without further downscaling. Please note that if the size defined by `minsize` is greater than the font size defined by trace, then the `minsize` is used.

    separators

    Parent: layout Type: string Sets the decimal and thousand separators. For example, ". " puts a '.' before decimals and a space between thousands. In English locales, dflt is ".," but other locales may alter this default.

    paper_bgcolor

    Parent: layout Type: color Default: "#fff" Sets the background color of the paper where the graph is drawn.

    plot_bgcolor

    Parent: layout Type: color Default: "#fff" Sets the background color of the plotting area in-between x and y axes.

    autotypenumbers

    Parent: layout Type: enumerated , one of ( "convert types" | "strict" ) Default: "convert types" Using "strict" a numeric string in trace data is not converted to a number. Using "convert types" a numeric string in trace data may be treated as a number during automatic axis `type` detection. This is the default value; however it could be overridden for individual axes.

    colorscale

    Parent: layout Type: object containing one or more of the keys listed below.

     diverging

    Parent: layout.colorscale Type: colorscale Default: [[0, rgb(5,10,172)], [0.35, rgb(106,137,247)], [0.5, rgb(190,190,190)], [0.6, rgb(220,170,132)], [0.7, rgb(230,145,90)], [1, rgb(178,10,28)], ] Sets the default diverging colorscale. Note that `autocolorscale` must be true for this attribute to work.

     sequential

    Parent: layout.colorscale Type: colorscale Default: [[0, rgb(220,220,220)], [0.2, rgb(245,195,157)], [0.4, rgb(245,160,105)], [1, rgb(178,10,28)], ] Sets the default sequential colorscale for positive values. Note that `autocolorscale` must be true for this attribute to work.

     sequentialminus

    Parent: layout.colorscale Type: colorscale Default: [[0, rgb(5,10,172)], [0.35, rgb(40,60,190)], [0.5, rgb(70,100,245)], [0.6, rgb(90,120,245)], [0.7, rgb(106,137,247)], [1, rgb(220,220,220)], ] Sets the default sequential colorscale for negative values. Note that `autocolorscale` must be true for this attribute to work.

    colorway

    Parent: layout Type: colorlist Default: [#1f77b4, #ff7f0e, #2ca02c, #d62728, #9467bd, #8c564b, #e377c2, #7f7f7f, #bcbd22, #17becf] Sets the default trace colors.

    modebar

    Parent: layout Type: object containing one or more of the keys listed below.

     activecolor

    Parent: layout.modebar Type: color Sets the color of the active or hovered on icons in the modebar.

     add

    Parent: layout.modebar Type: string or array of strings Default: "" Determines which predefined modebar buttons to add. Please note that these buttons will only be shown if they are compatible with all trace types used in a graph. Similar to `config.modeBarButtonsToAdd` option. This may include "v1hovermode", "hoverclosest", "hovercompare", "togglehover", "togglespikelines", "drawline", "drawopenpath", "drawclosedpath", "drawcircle", "drawrect", "eraseshape".

     bgcolor

    Parent: layout.modebar Type: color Sets the background color of the modebar.

     color

    Parent: layout.modebar Type: color Sets the color of the icons in the modebar.

     orientation

    Parent: layout.modebar Type: enumerated , one of ( "v" | "h" ) Default: "h" Sets the orientation of the modebar.

     remove

    Parent: layout.modebar Type: string or array of strings Default: "" Determines which predefined modebar buttons to remove. Similar to `config.modeBarButtonsToRemove` option. This may include "autoScale2d", "autoscale", "editInChartStudio", "editinchartstudio", "hoverCompareCartesian", "hovercompare", "lasso", "lasso2d", "orbitRotation", "orbitrotation", "pan", "pan2d", "pan3d", "reset", "resetCameraDefault3d", "resetCameraLastSave3d", "resetGeo", "resetSankeyGroup", "resetScale2d", "resetViewMapbox", "resetViews", "resetcameradefault", "resetcameralastsave", "resetsankeygroup", "resetscale", "resetview", "resetviews", "select", "select2d", "sendDataToCloud", "senddatatocloud", "tableRotation", "tablerotation", "toImage", "toggleHover", "toggleSpikelines", "togglehover", "togglespikelines", "toimage", "zoom", "zoom2d", "zoom3d", "zoomIn2d", "zoomInGeo", "zoomInMapbox", "zoomOut2d", "zoomOutGeo", "zoomOutMapbox", "zoomin", "zoomout".

     uirevision

    Parent: layout.modebar Type: number or categorical coordinate string Controls persistence of user-driven changes related to the modebar, including `hovermode`, `dragmode`, and `showspikes` at both the root level and inside subplots. Defaults to `layout.uirevision`.

    hovermode

    Parent: layout Type: enumerated , one of ( "x" | "y" | "closest" | false | "x unified" | "y unified" ) Default: "closest" Determines the mode of hover interactions. If "closest", a single hoverlabel will appear for the "closest" point within the `hoverdistance`. If "x" (or "y"), multiple hoverlabels will appear for multiple points at the "closest" x- (or y-) coordinate within the `hoverdistance`, with the caveat that no more than one hoverlabel will appear per trace. If "x unified" (or "y unified"), a single hoverlabel will appear multiple points at the closest x- (or y-) coordinate within the `hoverdistance` with the caveat that no more than one hoverlabel will appear per trace. In this mode, spikelines are enabled by default perpendicular to the specified axis. If false, hover interactions are disabled.

    hoversubplots

    Parent: layout Type: enumerated , one of ( "single" | "overlaying" | "axis" ) Default: "overlaying" Determines expansion of hover effects to other subplots If "single" just the axis pair of the primary point is included without overlaying subplots. If "overlaying" all subplots using the main axis and occupying the same space are included. If "axis", also include stacked subplots using the same axis when `hovermode` is set to "x", "x unified", "y" or "y unified".

    clickmode

    Parent: layout Type: flaglist string. Any combination of "event", "select" joined with a "+" OR "none". Examples: "event", "select", "event+select", "none" Default: "event" Determines the mode of single click interactions. "event" is the default value and emits the `plotly_click` event. In addition this mode emits the `plotly_selected` event in drag modes "lasso" and "select", but with no event data attached (kept for compatibility reasons). The "select" flag enables selecting single data points via click. This mode also supports persistent selections, meaning that pressing Shift while clicking, adds to / subtracts from an existing selection. "select" with `hovermode`: "x" can be confusing, consider explicitly setting `hovermode`: "closest" when using this feature. Selection events are sent accordingly as long as "event" flag is set as well. When the "event" flag is missing, `plotly_click` and `plotly_selected` events are not fired.

    dragmode

    Parent: layout Type: enumerated , one of ( "zoom" | "pan" | "select" | "lasso" | "drawclosedpath" | "drawopenpath" | "drawline" | "drawrect" | "drawcircle" | "orbit" | "turntable" | false ) Default: "zoom" Determines the mode of drag interactions. "select" and "lasso" apply only to scatter traces with markers or text. "orbit" and "turntable" apply only to 3D scenes.

    selectdirection

    Parent: layout Type: enumerated , one of ( "h" | "v" | "d" | "any" ) Default: "any" When `dragmode` is set to "select", this limits the selection of the drag to horizontal, vertical or diagonal. "h" only allows horizontal selection, "v" only vertical, "d" only diagonal and "any" sets no limit.

    activeselection

    Parent: layout Type: object containing one or more of the keys listed below.

     fillcolor

    Parent: layout.activeselection Type: color Default: "rgba(0,0,0,0)" Sets the color filling the active selection' interior.

     opacity

    Parent: layout.activeselection Type: number between or equal to 0 and 1 Default: 0.5 Sets the opacity of the active selection.

    newselection

    Parent: layout Type: object containing one or more of the keys listed below.

     line

    Parent: layout.newselection Type: object containing one or more of the keys listed below.

      color

    Parent: layout.newselection.line Type: color Sets the line color. By default uses either dark grey or white to increase contrast with background color.

      dash

    Parent: layout.newselection.line Type: string Default: "dot" Sets the dash style of lines. Set to a dash type string ("solid", "dot", "dash", "longdash", "dashdot", or "longdashdot") or a dash length list in px (eg "5px,10px,2px,2px").

      width

    Parent: layout.newselection.line Type: number greater than or equal to 1 Default: 1 Sets the line width (in px).

     mode

    Parent: layout.newselection Type: enumerated , one of ( "immediate" | "gradual" ) Default: "immediate" Describes how a new selection is created. If `immediate`, a new selection is created after first mouse up. If `gradual`, a new selection is not created after first mouse. By adding to and subtracting from the initial selection, this option allows declaring extra outlines of the selection.

    hoverdistance

    Parent: layout Type: integer greater than or equal to -1 Default: 20 Sets the default distance (in pixels) to look for data to add hover labels (-1 means no cutoff, 0 means no looking for data). This is only a real distance for hovering on point-like objects, like scatter points. For area-like objects (bars, scatter fills, etc) hovering is on inside the area and off outside, but these objects will not supersede hover on point-like objects in case of conflict.

    spikedistance

    Parent: layout Type: integer greater than or equal to -1 Default: -1 Sets the default distance (in pixels) to look for data to draw spikelines to (-1 means no cutoff, 0 means no looking for data). As with hoverdistance, distance does not apply to area-like objects. In addition, some objects can be hovered on but will not generate spikelines, such as scatter fills.

    hoverlabel

    Parent: layout Type: object containing one or more of the keys listed below.

     align

    Parent: layout.hoverlabel Type: enumerated , one of ( "left" | "right" | "auto" ) Default: "auto" Sets the horizontal alignment of the text content within hover label box. Has an effect only if the hover label text spans more two or more lines

     bgcolor

    Parent: layout.hoverlabel Type: color Sets the background color of all hover labels on graph

     bordercolor

    Parent: layout.hoverlabel Type: color Sets the border color of all hover labels on graph.

     font

    Parent: layout.hoverlabel Type: object containing one or more of the keys listed below. Sets the default hover label font used by all traces on the graph.

      color

    Parent: layout.hoverlabel.font Type: color

      family

    Parent: layout.hoverlabel.font Type: string Default: "Arial, sans-serif" HTML font family - the typeface that will be applied by the web browser. The web browser will only be able to apply a font if it is available on the system which it operates. Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts if they aren't available on the system. The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server, where only a select number of fonts are installed and supported. These include "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman".

      lineposition

    Parent: layout.hoverlabel.font Type: flaglist string. Any combination of "under", "over", "through" joined with a "+" OR "none". Examples: "under", "over", "under+over", "under+over+through", "none" Default: "none" Sets the kind of decoration line(s) with text, such as an "under", "over" or "through" as well as combinations e.g. "under+over", etc.

      shadow

    Parent: layout.hoverlabel.font Type: string Default: "none" Sets the shape and color of the shadow behind text. "auto" places minimal shadow and applies contrast text font color. See https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow for additional options.

      size

    Parent: layout.hoverlabel.font Type: number greater than or equal to 1 Default: 13

      style

    Parent: layout.hoverlabel.font Type: enumerated , one of ( "normal" | "italic" ) Default: "normal" Sets whether a font should be styled with a normal or italic face from its family.

      textcase

    Parent: layout.hoverlabel.font Type: enumerated , one of ( "normal" | "word caps" | "upper" | "lower" ) Default: "normal" Sets capitalization of text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

      variant

    Parent: layout.hoverlabel.font Type: enumerated , one of ( "normal" | "small-caps" | "all-small-caps" | "all-petite-caps" | "petite-caps" | "unicase" ) Default: "normal" Sets the variant of the font.

      weight

    Parent: layout.hoverlabel.font Type: integer between or equal to 1 and 1000 Default: normal Sets the weight (or boldness) of the font.

     grouptitlefont

    Parent: layout.hoverlabel Type: object containing one or more of the keys listed below. Sets the font for group titles in hover (unified modes). Defaults to `hoverlabel.font`.

      color

    Parent: layout.hoverlabel.grouptitlefont Type: color

      family

    Parent: layout.hoverlabel.grouptitlefont Type: string HTML font family - the typeface that will be applied by the web browser. The web browser will only be able to apply a font if it is available on the system which it operates. Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts if they aren't available on the system. The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server, where only a select number of fonts are installed and supported. These include "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman".

      lineposition

    Parent: layout.hoverlabel.grouptitlefont Type: flaglist string. Any combination of "under", "over", "through" joined with a "+" OR "none". Examples: "under", "over", "under+over", "under+over+through", "none" Default: "none" Sets the kind of decoration line(s) with text, such as an "under", "over" or "through" as well as combinations e.g. "under+over", etc.

      shadow

    Parent: layout.hoverlabel.grouptitlefont Type: string Default: "none" Sets the shape and color of the shadow behind text. "auto" places minimal shadow and applies contrast text font color. See https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow for additional options.

      size

    Parent: layout.hoverlabel.grouptitlefont Type: number greater than or equal to 1

      style

    Parent: layout.hoverlabel.grouptitlefont Type: enumerated , one of ( "normal" | "italic" ) Default: "normal" Sets whether a font should be styled with a normal or italic face from its family.

      textcase

    Parent: layout.hoverlabel.grouptitlefont Type: enumerated , one of ( "normal" | "word caps" | "upper" | "lower" ) Default: "normal" Sets capitalization of text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

      variant

    Parent: layout.hoverlabel.grouptitlefont Type: enumerated , one of ( "normal" | "small-caps" | "all-small-caps" | "all-petite-caps" | "petite-caps" | "unicase" ) Default: "normal" Sets the variant of the font.

      weight

    Parent: layout.hoverlabel.grouptitlefont Type: integer between or equal to 1 and 1000 Default: normal Sets the weight (or boldness) of the font.

     namelength

    Parent: layout.hoverlabel Type: integer greater than or equal to -1 Default: 15 Sets the default length (in number of characters) of the trace name in the hover labels for all traces. -1 shows the whole name regardless of length. 0-3 shows the first 0-3 characters, and an integer >3 will show the whole name if it is less than that many characters, but if it is longer, will truncate to `namelength - 3` characters and add an ellipsis.

    transition

    Parent: layout Type: object containing one or more of the keys listed below. Sets transition options used during Plotly.react updates.

     duration

    Parent: layout.transition Type: number greater than or equal to 0 Default: 500 The duration of the transition, in milliseconds. If equal to zero, updates are synchronous.

     easing

    Parent: layout.transition Type: enumerated , one of ( "linear" | "quad" | "cubic" | "sin" | "exp" | "circle" | "elastic" | "back" | "bounce" | "linear-in" | "quad-in" | "cubic-in" | "sin-in" | "exp-in" | "circle-in" | "elastic-in" | "back-in" | "bounce-in" | "linear-out" | "quad-out" | "cubic-out" | "sin-out" | "exp-out" | "circle-out" | "elastic-out" | "back-out" | "bounce-out" | "linear-in-out" | "quad-in-out" | "cubic-in-out" | "sin-in-out" | "exp-in-out" | "circle-in-out" | "elastic-in-out" | "back-in-out" | "bounce-in-out" ) Default: "cubic-in-out" The easing function used for the transition

     ordering

    Parent: layout.transition Type: enumerated , one of ( "layout first" | "traces first" ) Default: "layout first" Determines whether the figure's layout or traces smoothly transitions during updates that make both traces and layout change.

    datarevision

    Parent: layout Type: number or categorical coordinate string If provided, a changed value tells `Plotly.react` that one or more data arrays has changed. This way you can modify arrays in-place rather than making a complete new copy for an incremental change. If NOT provided, `Plotly.react` assumes that data arrays are being treated as immutable, thus any data array with a different identity from its predecessor contains new data.

    uirevision

    Parent: layout Type: number or categorical coordinate string Used to allow user interactions with the plot to persist after `Plotly.react` calls that are unaware of these interactions. If `uirevision` is omitted, or if it is given and it changed from the previous `Plotly.react` call, the exact new figure is used. If `uirevision` is truthy and did NOT change, any attribute that has been affected by user interactions and did not receive a different value in the new figure will keep the interaction value. `layout.uirevision` attribute serves as the default for `uirevision` attributes in various sub-containers. For finer control you can set these sub-attributes directly. For example, if your app separately controls the data on the x and y axes you might set `xaxis.uirevision="time"` and `yaxis.uirevision="cost"`. Then if only the y data is changed, you can update `yaxis.uirevision="quantity"` and the y axis range will reset but the x axis range will retain any user-driven zoom.

    editrevision

    Parent: layout Type: number or categorical coordinate string Controls persistence of user-driven changes in `editable: true` configuration, other than trace names and axis titles. Defaults to `layout.uirevision`.

    selectionrevision

    Parent: layout Type: number or categorical coordinate string Controls persistence of user-driven changes in selected points from all traces.

    template

    Parent: layout Type: number or categorical coordinate string Default attributes to be applied to the plot. Templates can be created from existing plots using `Plotly.makeTemplate`, or created manually. They should be objects with format: `{layout: layoutTemplate, data: {[type]: [traceTemplate, ...]}, ...}` `layoutTemplate` and `traceTemplate` are objects matching the attribute structure of `layout` and a data trace. Trace templates are applied cyclically to traces of each type. Container arrays (eg `annotations`) have special handling: An object ending in `defaults` (eg `annotationdefaults`) is applied to each array item. But if an item has a `templateitemname` key we look in the template array for an item with matching `name` and apply that instead. If no matching `name` is found we mark the item invisible. Any named template item not referenced is appended to the end of the array, so you can use this for a watermark annotation or a logo image, for example. To omit one of these items on the plot, make an item with matching `templateitemname` and `visible: false`.

    meta

    Parent: layout Type: number or categorical coordinate string Assigns extra meta information that can be used in various `text` attributes. Attributes such as the graph, axis and colorbar `title.text`, annotation `text` `trace.name` in legend items, `rangeselector`, `updatemenus` and `sliders` `label` text all support `meta`. One can access `meta` fields using template strings: `%{meta[i]}` where `i` is the index of the `meta` item in question. `meta` can also be an object for example `{key: value}` which can be accessed %{meta[key]}.

    computed

    Parent: layout Type: number or categorical coordinate string Placeholder for exporting automargin-impacting values namely `margin.t`, `margin.b`, `margin.l` and `margin.r` in "full-json" mode.

    grid

    Parent: layout Type: object containing one or more of the keys listed below.

     columns

    Parent: layout.grid Type: integer greater than or equal to 1 The number of columns in the grid. If you provide a 2D `subplots` array, the length of its longest row is used as the default. If you give an `xaxes` array, its length is used as the default. But it's also possible to have a different length, if you want to leave a row at the end for non-cartesian subplots.

     domain

    Parent: layout.grid Type: object containing one or more of the keys listed below.

      x

    Parent: layout.grid.domain Type: array Default: [0, 1] Sets the horizontal domain of this grid subplot (in plot fraction). The first and last cells end exactly at the domain edges, with no grout around the edges.

      y

    Parent: layout.grid.domain Type: array Default: [0, 1] Sets the vertical domain of this grid subplot (in plot fraction). The first and last cells end exactly at the domain edges, with no grout around the edges.

     pattern

    Parent: layout.grid Type: enumerated , one of ( "independent" | "coupled" ) Default: "coupled" If no `subplots`, `xaxes`, or `yaxes` are given but we do have `rows` and `columns`, we can generate defaults using consecutive axis IDs, in two ways: "coupled" gives one x axis per column and one y axis per row. "independent" uses a new xy pair for each cell, left-to-right across each row then iterating rows according to `roworder`.

     roworder

    Parent: layout.grid Type: enumerated , one of ( "top to bottom" | "bottom to top" ) Default: "top to bottom" Is the first row the top or the bottom? Note that columns are always enumerated from left to right.

     rows

    Parent: layout.grid Type: integer greater than or equal to 1 The number of rows in the grid. If you provide a 2D `subplots` array or a `yaxes` array, its length is used as the default. But it's also possible to have a different length, if you want to leave a row at the end for non-cartesian subplots.

     subplots

    Parent: layout.grid Type: array Used for freeform grids, where some axes may be shared across subplots but others are not. Each entry should be a cartesian subplot id, like "xy" or "x3y2", or "" to leave that cell empty. You may reuse x axes within the same column, and y axes within the same row. Non-cartesian subplots and traces that support `domain` can place themselves in this grid separately using the `gridcell` attribute.

     xaxes

    Parent: layout.grid Type: array Used with `yaxes` when the x and y axes are shared across columns and rows. Each entry should be an x axis id like "x", "x2", etc., or "" to not put an x axis in that column. Entries other than "" must be unique. Ignored if `subplots` is present. If missing but `yaxes` is present, will generate consecutive IDs.

     xgap

    Parent: layout.grid Type: number between or equal to 0 and 1 Horizontal space between grid cells, expressed as a fraction of the total width available to one cell. Defaults to 0.1 for coupled-axes grids and 0.2 for independent grids.

     xside

    Parent: layout.grid Type: enumerated , one of ( "bottom" | "bottom plot" | "top plot" | "top" ) Default: "bottom plot" Sets where the x axis labels and titles go. "bottom" means the very bottom of the grid. "bottom plot" is the lowest plot that each x axis is used in. "top" and "top plot" are similar.

     yaxes

    Parent: layout.grid Type: array Used with `yaxes` when the x and y axes are shared across columns and rows. Each entry should be an y axis id like "y", "y2", etc., or "" to not put a y axis in that row. Entries other than "" must be unique. Ignored if `subplots` is present. If missing but `xaxes` is present, will generate consecutive IDs.

     ygap

    Parent: layout.grid Type: number between or equal to 0 and 1 Vertical space between grid cells, expressed as a fraction of the total height available to one cell. Defaults to 0.1 for coupled-axes grids and 0.3 for independent grids.

     yside

    Parent: layout.grid Type: enumerated , one of ( "left" | "left plot" | "right plot" | "right" ) Default: "left plot" Sets where the y axis labels and titles go. "left" means the very left edge of the grid. "left plot" is the leftmost plot that each y axis is used in. "right" and "right plot" are similar.

    calendar

    Parent: layout Type: enumerated , one of ( "chinese" | "coptic" | "discworld" | "ethiopian" | "gregorian" | "hebrew" | "islamic" | "jalali" | "julian" | "mayan" | "nanakshahi" | "nepali" | "persian" | "taiwan" | "thai" | "ummalqura" ) Default: "gregorian" Sets the default calendar system to use for interpreting and displaying dates throughout the plot.

    minreducedheight

    Parent: layout Type: number greater than or equal to 2 Default: 64 Minimum height of the plot with margin.automargin applied (in px)

    minreducedwidth

    Parent: layout Type: number greater than or equal to 2 Default: 64 Minimum width of the plot with margin.automargin applied (in px)

    newshape

    Parent: layout Type: object containing one or more of the keys listed below.

     drawdirection

    Parent: layout.newshape Type: enumerated , one of ( "ortho" | "horizontal" | "vertical" | "diagonal" ) Default: "diagonal" When `dragmode` is set to "drawrect", "drawline" or "drawcircle" this limits the drag to be horizontal, vertical or diagonal. Using "diagonal" there is no limit e.g. in drawing lines in any direction. "ortho" limits the draw to be either horizontal or vertical. "horizontal" allows horizontal extend. "vertical" allows vertical extend.

     fillcolor

    Parent: layout.newshape Type: color Default: "rgba(0,0,0,0)" Sets the color filling new shapes' interior. Please note that if using a fillcolor with alpha greater than half, drag inside the active shape starts moving the shape underneath, otherwise a new shape could be started over.

     fillrule

    Parent: layout.newshape Type: enumerated , one of ( "evenodd" | "nonzero" ) Default: "evenodd" Determines the path's interior. For more info please visit https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule

     label

    Parent: layout.newshape Type: object containing one or more of the keys listed below.

      font

    Parent: layout.newshape.label Type: object containing one or more of the keys listed below. Sets the new shape label text font.

       color

    Parent: layout.newshape.label.font Type: color

       family

    Parent: layout.newshape.label.font Type: string HTML font family - the typeface that will be applied by the web browser. The web browser will only be able to apply a font if it is available on the system which it operates. Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts if they aren't available on the system. The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server, where only a select number of fonts are installed and supported. These include "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman".

       lineposition

    Parent: layout.newshape.label.font Type: flaglist string. Any combination of "under", "over", "through" joined with a "+" OR "none". Examples: "under", "over", "under+over", "under+over+through", "none" Default: "none" Sets the kind of decoration line(s) with text, such as an "under", "over" or "through" as well as combinations e.g. "under+over", etc.

       shadow

    Parent: layout.newshape.label.font Type: string Default: "none" Sets the shape and color of the shadow behind text. "auto" places minimal shadow and applies contrast text font color. See https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow for additional options.

       size

    Parent: layout.newshape.label.font Type: number greater than or equal to 1

       style

    Parent: layout.newshape.label.font Type: enumerated , one of ( "normal" | "italic" ) Default: "normal" Sets whether a font should be styled with a normal or italic face from its family.

       textcase

    Parent: layout.newshape.label.font Type: enumerated , one of ( "normal" | "word caps" | "upper" | "lower" ) Default: "normal" Sets capitalization of text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

       variant

    Parent: layout.newshape.label.font Type: enumerated , one of ( "normal" | "small-caps" | "all-small-caps" | "all-petite-caps" | "petite-caps" | "unicase" ) Default: "normal" Sets the variant of the font.

       weight

    Parent: layout.newshape.label.font Type: integer between or equal to 1 and 1000 Default: normal Sets the weight (or boldness) of the font. padding Parent: layout.newshape.label Type: number greater than or equal to 0 Default: 3 Sets padding (in px) between edge of label and edge of new shape.

      text

    Parent: layout.newshape.label Type: string Default: "" Sets the text to display with the new shape. It is also used for legend item if `name` is not provided.

      textangle

    Parent: layout.newshape.label Type: angle Default: "auto" Sets the angle at which the label text is drawn with respect to the horizontal. For lines, angle "auto" is the same angle as the line. For all other shapes, angle "auto" is horizontal.

      textposition

    Parent: layout.newshape.label Type: enumerated , one of ( "top left" | "top center" | "top right" | "middle left" | "middle center" | "middle right" | "bottom left" | "bottom center" | "bottom right" | "start" | "middle" | "end" ) Sets the position of the label text relative to the new shape. Supported values for rectangles, circles and paths are "top left", "top center", "top right", "middle left", "middle center", "middle right", "bottom left", "bottom center", and "bottom right". Supported values for lines are "start", "middle", and "end". Default: "middle center" for rectangles, circles, and paths; "middle" for lines.

      texttemplate

    Parent: layout.newshape.label Type: string Default: "" Template string used for rendering the new shape's label. Note that this will override `text`. Variables are inserted using %{variable}, for example "x0: %{x0}". Numbers are formatted using d3-format's syntax %{variable:d3-format}, for example "Price: %{x0:$.2f}". See https://github.com/d3/d3-format/tree/v1.4.5#d3-format for details on the formatting syntax. Dates are formatted using d3-time-format's syntax %{variable|d3-time-format}, for example "Day: %{x0|%m %b %Y}". See https://github.com/d3/d3-time-format/tree/v2.2.3#locale_format for details on the date formatting syntax. A single multiplication or division operation may be applied to numeric variables, and combined with d3 number formatting, for example "Length in cm: %{x0"2.54}", "%{slope"60:.1f} meters per second." For log axes, variable values are given in log units. For date axes, x/y coordinate variables and center variables use datetimes, while all other variable values use values in ms. Finally, the template string has access to variables `x0`, `x1`, `y0`, `y1`, `slope`, `dx`, `dy`, `width`, `height`, `length`, `xcenter` and `ycenter`.

      xanchor

    Parent: layout.newshape.label Type: enumerated , one of ( "auto" | "left" | "center" | "right" ) Default: "auto" Sets the label's horizontal position anchor This anchor binds the specified `textposition` to the "left", "center" or "right" of the label text. For example, if `textposition` is set to "top right" and `xanchor` to "right" then the right-most portion of the label text lines up with the right-most edge of the new shape.

      yanchor

    Parent: layout.newshape.label Type: enumerated , one of ( "top" | "middle" | "bottom" ) Sets the label's vertical position anchor This anchor binds the specified `textposition` to the "top", "middle" or "bottom" of the label text. For example, if `textposition` is set to "top right" and `yanchor` to "top" then the top-most portion of the label text lines up with the top-most edge of the new shape.

     layer

    Parent: layout.newshape Type: enumerated , one of ( "below" | "above" | "between" ) Default: "above" Specifies whether new shapes are drawn below gridlines ("below"), between gridlines and traces ("between") or above traces ("above").

     legend

    Parent: layout.newshape Type: subplotid Default: legend Sets the reference to a legend to show new shape in. References to these legends are "legend", "legend2", "legend3", etc. Settings for these legends are set in the layout, under `layout.legend`, `layout.legend2`, etc.

     legendgroup

    Parent: layout.newshape Type: string Default: "" Sets the legend group for new shape. Traces and shapes part of the same legend group hide/show at the same time when toggling legend items.

     legendgrouptitle

    Parent: layout.newshape Type: object containing one or more of the keys listed below.

      font

    Parent: layout.newshape.legendgrouptitle Type: object containing one or more of the keys listed below. Sets this legend group's title font.

       color

    Parent: layout.newshape.legendgrouptitle.font Type: color

       family

    Parent: layout.newshape.legendgrouptitle.font Type: string HTML font family - the typeface that will be applied by the web browser. The web browser will only be able to apply a font if it is available on the system which it operates. Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts if they aren't available on the system. The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server, where only a select number of fonts are installed and supported. These include "Arial", "Balto", "Courier New", "Droid Sans", "Droid Serif", "Droid Sans Mono", "Gravitas One", "Old Standard TT", "Open Sans", "Overpass", "PT Sans Narrow", "Raleway", "Times New Roman".

       lineposition

    Parent: layout.newshape.legendgrouptitle.font Type: flaglist string. Any combination of "under", "over", "through" joined with a "+" OR "none". Examples: "under", "over", "under+over", "under+over+through", "none" Default: "none" Sets the kind of decoration line(s) with text, such as an "under", "over" or "through" as well as combinations e.g. "under+over", etc.

       shadow

    Parent: layout.newshape.legendgrouptitle.font Type: string Default: "none" Sets the shape and color of the shadow behind text. "auto" places minimal shadow and applies contrast text font color. See https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow for additional options.

       size

    Parent: layout.newshape.legendgrouptitle.font Type: number greater than or equal to 1

       style

    Parent: layout.newshape.legendgrouptitle.font Type: enumerated , one of ( "normal" | "italic" ) Default: "normal" Sets whether a font should be styled with a normal or italic face from its family.

       textcase

    Parent: layout.newshape.legendgrouptitle.font Type: enumerated , one of ( "normal" | "word caps" | "upper" | "lower" ) Default: "normal" Sets capitalization of text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized.

       variant

    Parent: layout.newshape.legendgrouptitle.font Type: enumerated , one of ( "normal" | "small-caps" | "all-small-caps" | "all-petite-caps" | "petite-caps" | "unicase" ) Default: "normal" Sets the variant of the font.

       weight

    Parent: layout.newshape.legendgrouptitle.font Type: integer between or equal to 1 and 1000 Default: normal Sets the weight (or boldness) of the font.

      text

    Parent: layout.newshape.legendgrouptitle Type: string Default: "" Sets the title of the legend group.

     legendrank

    Parent: layout.newshape Type: number Default: 1000 Sets the legend rank for new shape. Items and groups with smaller ranks are presented on top/left side while with "reversed" `legend.traceorder` they are on bottom/right side. The default legendrank is 1000, so that you can use ranks less than 1000 to place certain items before all unranked items, and ranks greater than 1000 to go after all unranked items.

     legendwidth

    Parent: layout.newshape Type: number greater than or equal to 0 Sets the width (in px or fraction) of the legend for new shape.

     line

    Parent: layout.newshape Type: object containing one or more of the keys listed below.

      color

    Parent: layout.newshape.line Type: color Sets the line color. By default uses either dark grey or white to increase contrast with background color.

      dash

    Parent: layout.newshape.line Type: string Default: "solid" Sets the dash style of lines. Set to a dash type string ("solid", "dot", "dash", "longdash", "dashdot", or "longdashdot") or a dash length list in px (eg "5px,10px,2px,2px").

      width

    Parent: layout.newshape.line Type: number greater than or equal to 0 Default: 4 Sets the line width (in px).

     name

    Parent: layout.newshape Type: string Sets new shape name. The name appears as the legend item.

     opacity

    Parent: layout.newshape Type: number between or equal to 0 and 1 Default: 1 Sets the opacity of new shapes.

     showlegend

    Parent: layout.newshape Type: boolean Determines whether or not new shape is shown in the legend.

     visible

    Parent: layout.newshape Type: enumerated , one of ( true | false | "legendonly" ) Default: true Determines whether or not new shape is visible. If "legendonly", the shape is not drawn, but can appear as a legend item (provided that the legend itself is visible).

    activeshape

    Parent: layout Type: object containing one or more of the keys listed below.

     fillcolor

    Parent: layout.activeshape Type: color Default: "rgb(255,0,255)" Sets the color filling the active shape' interior.

     opacity

    Parent: layout.activeshape Type: number between or equal to 0 and 1 Default: 0.5 Sets the opacity of the active shape.

    selections

    Parent: layout Type: array of object where each object has one or more of the keys listed below. This will break if there ever more than one type of item in in items - but for now it's just "shape" and "annotation"

     line

    Parent: layout.selections[] Type: object containing one or more of the keys listed below.

      color

    Parent: layout.selections[].line Type: color Sets the line color.

      dash

    Parent: layout.selections[].line Type: string Default: "dot" Sets the dash style of lines. Set to a dash type string ("solid", "dot", "dash", "longdash", "dashdot", or "longdashdot") or a dash length list in px (eg "5px,10px,2px,2px").

      width

    Parent: layout.selections[].line Type: number greater than or equal to 1 Default: 1 Sets the line width (in px).

     name

    Parent: layout.selections[] Type: string When used in a template, named items are created in the output figure in addition to any items the figure already has in this array. You can modify these items in the output figure by making your own item with `templateitemname` matching this `name` alongside your modifications (including `visible: false` or `enabled: false` to hide it). Has no effect outside of a template.

     opacity

    Parent: layout.selections[] Type: number between or equal to 0 and 1 Default: 0.7 Sets the opacity of the selection.

     path

    Parent: layout.selections[] Type: string For `type` "path" - a valid SVG path similar to `shapes.path` in data coordinates. Allowed segments are: M, L and Z.

     templateitemname

    Parent: layout.selections[] Type: string Used to refer to a named item in this array in the template. Named items from the template will be created even without a matching item in the input figure, but you can modify one by making an item with `templateitemname` matching its `name`, alongside your modifications (including `visible: false` or `enabled: false` to hide it). If there is no template or no matching item, this item will be hidden unless you explicitly show it with `visible: true`.

     type

    Parent: layout.selections[] Type: enumerated , one of ( "rect" | "path" ) Specifies the selection type to be drawn. If "rect", a rectangle is drawn linking (`x0`,`y0`), (`x1`,`y0`), (`x1`,`y1`) and (`x0`,`y1`). If "path", draw a custom SVG path using `path`.

     x0

    Parent: layout.selections[] Type: number or categorical coordinate string Sets the selection's starting x position.

     x1

    Parent: layout.selections[] Type: number or categorical coordinate string Sets the selection's end x position.

     xref

    Parent: layout.selections[] Type: enumerated , one of ( "paper" | "/^x([2-9]|[1-9][0-9]+)?( domain)?$/" ) Sets the selection's x coordinate axis. If set to a x axis id (e.g. "x" or "x2"), the `x` position refers to a x coordinate. If set to "paper", the `x` position refers to the distance from the left of the plotting area in normalized coordinates where "0" ("1") corresponds to the left (right). If set to a x axis ID followed by "domain" (separated by a space), the position behaves like for "paper", but refers to the distance in fractions of the domain length from the left of the domain of that axis: e.g., "x2 domain" refers to the domain of the second x axis and a x position of 0.5 refers to the point between the left and the right of the domain of the second x axis.

     y0

    Parent: layout.selections[] Type: number or categorical coordinate string Sets the selection's starting y position.

     y1

    Parent: layout.selections[] Type: number or categorical coordinate string Sets the selection's end y position.

     yref

    Parent: layout.selections[] Type: enumerated , one of ( "paper" | "/^y([2-9]|[1-9][0-9]+)?( domain)?$/" ) Sets the selection's x coordinate axis. If set to a y axis id (e.g. "y" or "y2"), the `y` position refers to a y coordinate. If set to "paper", the `y` position refers to the distance from the bottom of the plotting area in normalized coordinates where "0" ("1") corresponds to the bottom (top). If set to a y axis ID followed by "domain" (separated by a space), the position behaves like for "paper", but refers to the distance in fractions of the domain length from the bottom of the domain of that axis: e.g., "y2 domain" refers to the domain of the second y axis and a y position of 0.5 refers to the point between the bottom and the top of the domain of the second y axis.

    hidesources

    Parent: layout Type: boolean Determines whether or not a text link citing the data source is placed at the bottom-right cored of the figure. Has only an effect only on graphs that have been generated via forked graphs from the Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise).

    scattergap

    Parent: layout Type: number between or equal to 0 and 1 Sets the gap (in plot fraction) between scatter points of adjacent location coordinates. Defaults to `bargap`.

    scattermode

    Parent: layout Type: enumerated , one of ( "group" | "overlay" ) Default: "overlay" Determines how scatter points at the same location coordinate are displayed on the graph. With "group", the scatter points are plotted next to one another centered around the shared location. With "overlay", the scatter points are plotted over one another, you might need to reduce "opacity" to see multiple scatter points.

    barcornerradius

    Parent: layout Type: number or categorical coordinate string Sets the rounding of bar corners. May be an integer number of pixels, or a percentage of bar width (as a string ending in %).

    extendpiecolors

    Parent: layout Type: boolean Default: true If `true`, the pie slice colors (whether given by `piecolorway` or inherited from `colorway`) will be extended to three times its original length by first repeating every color 20% lighter then each color 20% darker. This is intended to reduce the likelihood of reusing the same color when you have many slices, but you can set `false` to disable. Colors provided in the trace, using `marker.colors`, are never extended.

    hiddenlabels

    Parent: layout Type: data array hiddenlabels is the funnelarea & pie chart analog of visible:'legendonly' but it can contain many labels, and can simultaneously hide slices from several pies/funnelarea charts

    piecolorway

    Parent: layout Type: colorlist Sets the default pie slice colors. Defaults to the main `colorway` used for trace colors. If you specify a new list here it can still be extended with lighter and darker colors, see `extendpiecolors`.

    violingap

    Parent: layout Type: number between or equal to 0 and 1 Default: 0.3 Sets the gap (in plot fraction) between violins of adjacent location coordinates. Has no effect on traces that have "width" set.

    violingroupgap

    Parent: layout Type: number between or equal to 0 and 1 Default: 0.3 Sets the gap (in plot fraction) between violins of the same location coordinate. Has no effect on traces that have "width" set.

    violinmode

    Parent: layout Type: enumerated , one of ( "group" | "overlay" ) Default: "overlay" Determines how violins at the same location coordinate are displayed on the graph. If "group", the violins are plotted next to one another centered around the shared location. If "overlay", the violins are plotted over one another, you might need to set "opacity" to see them multiple violins. Has no effect on traces that have "width" set.

    bargroupgap

    Parent: layout Type: number between or equal to 0 and 1 Default: 0 Sets the gap (in plot fraction) between bars of the same location coordinate.

    barmode

    Parent: layout Type: enumerated , one of ( "stack" | "group" | "overlay" | "relative" ) Default: "group" Determines how bars at the same location coordinate are displayed on the graph. With "stack", the bars are stacked on top of one another With "relative", the bars are stacked on top of one another, with negative values below the axis, positive values above With "group", the bars are plotted next to one another centered around the shared location. With "overlay", the bars are plotted over one another, you might need to reduce "opacity" to see multiple bars.

    barnorm

    Parent: layout Type: enumerated , one of ( "" | "fraction" | "percent" ) Default: "" Sets the normalization for bar traces on the graph. With "fraction", the value of each bar is divided by the sum of all values at that location coordinate. "percent" is the same but multiplied by 100 to show percentages.

    boxgap

    Parent: layout Type: number between or equal to 0 and 1 Default: 0.3 Sets the gap (in plot fraction) between boxes of adjacent location coordinates. Has no effect on traces that have "width" set.

    boxgroupgap

    Parent: layout Type: number between or equal to 0 and 1 Default: 0.3 Sets the gap (in plot fraction) between boxes of the same location coordinate. Has no effect on traces that have "width" set.

    boxmode

    Parent: layout Type: enumerated , one of ( "group" | "overlay" ) Default: "overlay" Determines how boxes at the same location coordinate are displayed on the graph. If "group", the boxes are plotted next to one another centered around the shared location. If "overlay", the boxes are plotted over one another, you might need to set "opacity" to see them multiple boxes. Has no effect on traces that have "width" set.

    waterfallgap

    Parent: layout Type: number between or equal to 0 and 1 Sets the gap (in plot fraction) between bars of adjacent location coordinates.

    waterfallgroupgap

    Parent: layout Type: number between or equal to 0 and 1 Default: 0 Sets the gap (in plot fraction) between bars of the same location coordinate.

    waterfallmode

    Parent: layout Type: enumerated , one of ( "group" | "overlay" ) Default: "group" Determines how bars at the same location coordinate are displayed on the graph. With "group", the bars are plotted next to one another centered around the shared location. With "overlay", the bars are plotted over one another, you might need to reduce "opacity" to see multiple bars.

    funnelgap

    Parent: layout Type: number between or equal to 0 and 1 Sets the gap (in plot fraction) between bars of adjacent location coordinates.

    funnelgroupgap

    Parent: layout Type: number between or equal to 0 and 1 Default: 0 Sets the gap (in plot fraction) between bars of the same location coordinate.

    funnelmode

    Parent: layout Type: enumerated , one of ( "stack" | "group" | "overlay" ) Default: "stack" Determines how bars at the same location coordinate are displayed on the graph. With "stack", the bars are stacked on top of one another With "group", the bars are plotted next to one another centered around the shared location. With "overlay", the bars are plotted over one another, you might need to reduce "opacity" to see multiple bars.

    extendfunnelareacolors

    Parent: layout Type: boolean Default: true If `true`, the funnelarea slice colors (whether given by `funnelareacolorway` or inherited from `colorway`) will be extended to three times its original length by first repeating every color 20% lighter then each color 20% darker. This is intended to reduce the likelihood of reusing the same color when you have many slices, but you can set `false` to disable. Colors provided in the trace, using `marker.colors`, are never extended.

    funnelareacolorway

    Parent: layout Type: colorlist Sets the default funnelarea slice colors. Defaults to the main `colorway` used for trace colors. If you specify a new list here it can still be extended with lighter and darker colors, see `extendfunnelareacolors`.

    bargap

    Parent: layout Type: number between or equal to 0 and 1 Default: 0.1 Sets the gap between bars of adjacent location coordinates. Values are unitless, they represent fractions of the minimum difference in bar positions in the data.

    extendsunburstcolors

    Parent: layout Type: boolean Default: true If `true`, the sunburst slice colors (whether given by `sunburstcolorway` or inherited from `colorway`) will be extended to three times its original length by first repeating every color 20% lighter then each color 20% darker. This is intended to reduce the likelihood of reusing the same color when you have many slices, but you can set `false` to disable. Colors provided in the trace, using `marker.colors`, are never extended.

    sunburstcolorway

    Parent: layout Type: colorlist Sets the default sunburst slice colors. Defaults to the main `colorway` used for trace colors. If you specify a new list here it can still be extended with lighter and darker colors, see `extendsunburstcolors`.

    extendtreemapcolors

    Parent: layout Type: boolean Default: true If `true`, the treemap slice colors (whether given by `treemapcolorway` or inherited from `colorway`) will be extended to three times its original length by first repeating every color 20% lighter then each color 20% darker. This is intended to reduce the likelihood of reusing the same color when you have many slices, but you can set `false` to disable. Colors provided in the trace, using `marker.colors`, are never extended.

    treemapcolorway

    Parent: layout Type: colorlist Sets the default treemap slice colors. Defaults to the main `colorway` used for trace colors. If you specify a new list here it can still be extended with lighter and darker colors, see `extendtreemapcolors`.

    extendiciclecolors

    Parent: layout Type: boolean Default: true If `true`, the icicle slice colors (whether given by `iciclecolorway` or inherited from `colorway`) will be extended to three times its original length by first repeating every color 20% lighter then each color 20% darker. This is intended to reduce the likelihood of reusing the same color when you have many slices, but you can set `false` to disable. Colors provided in the trace, using `marker.colors`, are never extended.

    iciclecolorway

    Parent: layout Type: colorlist Sets the default icicle slice colors. Defaults to the main `colorway` used for trace colors. If you specify a new list here it can still be extended with lighter and darker colors, see `extendiciclecolors`.

    Access Array of Objects

    Using the Brackets notation arrayName[arrayIndex] console.log(objArr[0]); Using the DOT notation arrayName[arrayIndex].propertyName console.log(objArr[1].gender); Using the for..in loop for (var key in arrayName) { console.log(arrayName[key].name); //Or we can access the specific properties using console.log(arrayName[arrayIndex].propertyName); } for (let key in objArr) { // Console logs all the values in the objArr Array: console.log(objArr[key]); } Using forEach Loop arrayName.forEach(function(item) { console.log(item); }); objArr.forEach(function(item) { console.log(item); }); Using map() method arrayName.map((item) => { console.log(item); }); objArr.map((item) => { console.log(item); }); Using filter() method arrayName.filter(function(item) { console.log(item); }); objArr.filter(function(item) { console.log(item); }); console.log("Using the Filer method to acces value") const search = objArr.filter(function(item) { return item.name === 'jane'; }); console.log(search);

    48 JavaScript code pieces


    Anagrams of string(带有重复项)

    用递归。 对于给定字符串中的每个字母,为字母创建字谜。 使用map()将字母与每部分字谜组合,然后使用reduce()将所有字谜组合到一个数组中,最基本情况是字符串长度等于2或1。 const anagrams = str => { if (str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : [str]; return str.split('').reduce((acc, letter, i) => acc.concat(anagrams(str.slice(0, i) + str.slice(i + 1)).map(val => letter + val)), []); }; // anagrams('abc') -> ['abc','acb','bac','bca','cab','cba']

    数组平均数

    用reduce()将每个值添加到累加器,初始值为0,总和除以数组长度。 const average = arr => arr.reduce((acc, val) => acc + val, 0) / arr.length; // average([1,2,3]) -> 2

    大写每个单词的首字母

    用replace()匹配每个单词的第一个字符,并使用toUpperCase()来将其大写。 const capitalizeEveryWord = str => str.replace(/\b[a-z]/g, char => char.toUpperCase()); // capitalizeEveryWord('hello world!') -> 'Hello World!'

    首字母大写

    用slice(0,1)和toUpperCase()大写第一个字母,slice(1)获取字符串的其余部分。 省略lowerRest参数以保持字符串的其余部分不变,或将其设置为true以转换为小写。 (注意:这和上一个示例不是同一件事情) const capitalize = (str, lowerRest = false) => str.slice(0, 1).toUpperCase() + (lowerRest ? str.slice(1).toLowerCase() : str.slice(1)); // capitalize(‘myName’, true) -> ‘Myname’

    检查回文

    字符串转换为toLowerCase(),并使用replace()从中删除非字母的字符。 然后,将其转换为tolowerCase(),将(’‘)拆分为单独字符,reverse(),join(’‘),与原始的非反转字符串进行比较,然后将其转换为tolowerCase()。 const palindrome = str => { const s = str.toLowerCase().replace(/[\W_]/g,''); return s === s.split('').reverse().join(''); } // palindrome('taco cat') -> true

    计数数组中值的出现次数

    次遇到数组中的特定值时,使用reduce()来递增计数器。 const countOccurrences = (arr, value) => arr.reduce((a, v) => v === value ? a + 1 : a + 0, 0); // countOccurrences([1,1,2,1,2,3], 1) -> 3

    当前URL

    用window.location.href来获取当前URL。 const currentUrl = _ => window.location.href; // currentUrl() -> 'https://google.com'

    Curry

    用递归。 如果提供的参数(args)数量足够,则调用传递函数f,否则返回一个curried函数f。 const curry = (fn, arity = fn.length, ...args) => arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args); // curry(Math.pow)(2)(10) -> 1024 // curry(Math.min, 3)(10)(50)(2) -> 2

    Deep flatten array

    用递归,使用reduce()来获取所有不是数组的元素,flatten每个元素都是数组。 const deepFlatten = arr => arr.reduce((a, v) => a.concat(Array.isArray(v) ? deepFlatten(v) : v), []); // deepFlatten([1,[2],[[3],4],5]) -> [1,2,3,4,5]

    数组之间的区别

    b创建一个Set,然后在a上使用Array.filter(),只保留b中不包含的值。 const difference = (a, b) => { const s = new Set(b); return a.filter(x => !s.has(x)); }; // difference([1,2,3], [1,2]) -> [3]

    两点之间的距离

    用Math.hypot()计算两点之间的欧几里德距离。 const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0); // distance(1,1, 2,3) -> 2.23606797749979

    可以按数字整除

    用模运算符(%)来检查余数是否等于0。 const isDivisible = (dividend, divisor) => dividend % divisor === 0; // isDivisible(6,3) -> true

    转义正则表达式

    用replace()来转义特殊字符。 const escapeRegExp = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // escapeRegExp('(test)') -> \\(test\\)

    偶数或奇数

    用Math.abs()将逻辑扩展为负数,使用模(%)运算符进行检查。 如果数字是偶数,则返回true; 如果数字是奇数,则返回false。 const isEven = num => num % 2 === 0; // isEven(3) -> false

    阶乘

    用递归。 如果n小于或等于1,则返回1。 否则返回n和n – 1的阶乘的乘积。 const factorial = n => n <= 1 ? 1 : n * factorial(n - 1); // factorial(6) -> 720

    斐波那契数组生成器

    建一个特定长度的空数组,初始化前两个值(0和1)。 使用Array.reduce()向数组中添加值,后面的一个数等于前面两个数相加之和(前两个除外)。 const fibonacci = n => Array(n).fill(0).reduce((acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), []); // fibonacci(5) -> [0,1,1,2,3]

    过滤数组中的非唯一值

    Array.filter()用于仅包含唯一值的数组。 const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i)); // filterNonUnique([1,2,2,3,4,4,5]) -> [1,3,5]

    Flatten数组

    用reduce()来获取数组中的所有元素,并使用concat()来使它们flatten。 const flatten = arr => arr.reduce((a, v) => a.concat(v), []); // flatten([1,[2],3,4]) -> [1,2,3,4]

    从数组中获取最大值

    用Math.max()与spread运算符(…)结合得到数组中的最大值。 const arrayMax = arr => Math.max(...arr); // arrayMax([10, 1, 5]) -> 10

    从数组中获取最小值

    用Math.min()与spread运算符(…)结合得到数组中的最小值。 const arrayMin = arr => Math.min(...arr); // arrayMin([10, 1, 5]) -> 1

    获取滚动位置

    果已定义,请使用pageXOffset和pageYOffset,否则使用scrollLeft和scrollTop,可以省略el来使用window的默认值。 const getScrollPos = (el = window) => ({x: (el.pageXOffset !== undefined) ? el.pageXOffset : el.scrollLeft, y: (el.pageYOffset !== undefined) ? el.pageYOffset : el.scrollTop}); // getScrollPos() -> {x: 0, y: 200}

    最大公约数(GCD)

    用递归。 基本情况是当y等于0时。 在这种情况下,返回x。 否则,返回y的GCD和x / y的其余部分。 const gcd = (x, y) => !y ? x : gcd(y, x % y); // gcd (8, 36) -> 4

    Head of list

    回ARR[0] const head = arr => arr[0]; // head([1,2,3]) -> 1

    list初始化

    回arr.slice(0,-1) const initial = arr => arr.slice(0, -1); // initial([1,2,3]) -> [1,2]

    用range初始化数组

    用Array(end-start)创建所需长度的数组,使用map()来填充范围中的所需值,可以省略start使用默认值0。 const initializeArrayRange = (end, start = 0) => Array.apply(null, Array(end - start)).map((v, i) => i + start); // initializeArrayRange(5) -> [0,1,2,3,4]

    用值初始化数组

    用Array(n)创建所需长度的数组,fill(v)以填充所需的值,可以忽略value使用默认值0。 const initializeArray = (n, value = 0) => Array(n).fill(value); // initializeArray(5, 2) -> [2,2,2,2,2]

    列表的最后

    回arr.slice(-1)[0] const last = arr => arr.slice(-1)[0]; // last([1,2,3]) -> 3

    测试功能所花费的时间

    用performance.now()获取函数的开始和结束时间,console.log()所花费的时间。 第一个参数是函数名,随后的参数传递给函数。 const timeTaken = callback => { console.time('timeTaken'); const r = callback(); console.timeEnd('timeTaken'); return r; }; // timeTaken(() => Math.pow(2, 10)) -> 1024 // (logged): timeTaken: 0.02099609375ms

    来自键值对的对象

    用Array.reduce()来创建和组合键值对。 const objectFromPairs = arr => arr.reduce((a, v) => (a[v[0]] = v[1], a), {}); // objectFromPairs([['a',1],['b',2]]) -> {a: 1, b: 2}

    管道

    用Array.reduce()通过函数传递值。 const pipe = (...funcs) => arg => funcs.reduce((acc, func) => func(acc), arg); // pipe(btoa, x => x.toUpperCase())("Test") -> "VGVZDA=="

    Powerset

    用reduce()与map()结合来遍历元素,并将其组合成包含所有组合的数组。 const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]); // powerset([1,2]) -> [[], [1], [2], [2,1]]

    范围内的随机整数

    用Math.random()生成一个随机数并将其映射到所需的范围,使用Math.floor()使其成为一个整数。 const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; // randomIntegerInRange(0, 5) -> 2

    范围内的随机数

    用Math.random()生成一个随机值,使用乘法将其映射到所需的范围。 const randomInRange = (min, max) => Math.random() * (max - min) + min; // randomInRange(2,10) -> 6.0211363285087005

    随机化数组的顺序

    用sort()重新排序元素,利用Math.random()来随机排序。 const shuffle = arr => arr.sort(() => Math.random() - 0.5); // shuffle([1,2,3]) -> [2,3,1]

    重定向到URL

    用window.location.href或window.location.replace()重定向到url。 传递第二个参数来模拟链接点击(true – default)或HTTP重定向(false)。 const redirect = (url, asLink = true) => asLink ? window.location.href = url : window.location.replace(url); // redirect('https://google.com')

    反转一个字符串

    用数组解构和Array.reverse()来颠倒字符串中的字符顺序。 合并字符以使用join(‘‘)获取字符串。 const reverseString = str => [...str].reverse().join(''); // reverseString('foobar') -> 'raboof'

    RGB到十六进制

    用按位左移运算符(«)和toString(16),然后padStart(6,“0”)将给定的RGB参数转换为十六进制字符串以获得6位十六进制值。 const rgbToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0'); // rgbToHex(255, 165, 1) -> 'ffa501'

    滚动到顶部

    用document.documentElement.scrollTop或document.body.scrollTop获取到顶部的距离。 顶部滚动一小部分距离。 用window.requestAnimationFrame()来滚动。 const scrollToTop = _ => { const c = document.documentElement.scrollTop || document.body.scrollTop; if (c > 0) { window.requestAnimationFrame(scrollToTop); window.scrollTo(0, c - c / 8); } }; // scrollToTop()

    随机数组值

    用Array.map()和Math.random()创建一个随机值的数组。 使用Array.sort()根据随机值对原始数组的元素进行排序。 count shuffle = arr => { let r = arr.map(Math.random); return arr.sort((a, b) => r[a] - r[b]); } // shuffle([1, 2, 3] -> [2, 1, 3])

    数组之间的相似性

    用filter()移除不是values的一部分值,使用includes()确定。 const similarity = (arr, values) => arr.filter(v => values.includes(v)); // similarity([1,2,3], [1,2,4]) -> [1,2]

    按字符串排序(按字母顺序排列)

    用split(’‘)分割字符串,sort()使用localeCompare(),使用join(’‘)重新组合。 const sortCharactersInString = str => str.split('').sort((a, b) => a.localeCompare(b)).join(''); // sortCharactersInString('cabbage') -> 'aabbceg'

    数组总和

    用reduce()将每个值添加到累加器,初始化值为0。 const sum = arr => arr.reduce((acc, val) => acc + val, 0); // sum([1,2,3,4]) -> 10

    交换两个变量的值

    用数组解构来交换两个变量之间的值。 [varA, varB] = [varB, varA]; // [x, y] = [y, x]

    列表的tail

    回arr.slice(1) const tail = arr => arr.length > 1 ? arr.slice(1) : arr; // tail([1,2,3]) -> [2,3] // tail([1]) -> [1]

    数组唯一值

    用ES6 Set和… rest操作符去掉所有重复值。 const unique = arr => [...new Set(arr)]; // unique([1,2,2,3,4,4,5]) -> [1,2,3,4,5]

    URL参数

    用match() 与适当的正则表达式来获得所有键值对,适当的map() 。 使用Object.assign()和spread运算符(…)将所有键值对组合到一个对象中,将location.search作为参数传递给当前url。 const getUrlParameters = url => url.match(/([^?=&]+)(=([^&]*))/g).reduce( (a, v) => (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1), a), {} ); // getUrlParameters('http://url.com/page?name=Adam&surname=Smith') -> {name: 'Adam', surname: 'Smith'} UID生成器 用crypto API生成符合RFC4122版本4的UUID。 const uuid = _ => ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); // uuid() -> '7982fcfe-5721-4632-bede-6000885be57d'

    验证数字

    用!isNaN和parseFloat()来检查参数是否是一个数字,使用isFinite()来检查数字是否是有限的。 const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n; // validateNumber('10') -> true

    Self-Invoking Functions

    The self-invoking functions are JavaScript functions that execute immediately as they are defined. A self-invoking expression is invoked (started) automatically, without being called. Function expressions will execute automatically if the expression is followed by (). You cannot self-invoke a function declaration. Syntax (function() { // function body })(); Example (function() { let x = "Hello!!"; })(); output Hello!! The function definition is enclosed inside the pair of parentheses. The second pair of parentheses at the end executes the function. Example We print the message in the output using the self-executing function. (function() { document.getElementById("output").innerHTML = "Self-invoked function is executed!"; }()); Output: Self-invoked function is executed! Self-Invoking Functions with Parameters It is common practice to pass references to global objects such as window, etc. (function(paras) { // function body })(args); Example We created an anonymous function with a parameter name. We have passed an argument to it. const output = document.getElementById("demo"); (function(name) { output.innerHTML = `Welcome to ${name}`; })("Tutorials Point !"); Output Welcome to Tutorials Point ! Private Scope of Self-Invoking Functions Whatever code is defined inside the self-executing function remains in the private scope and doesn't pollute the global scope. So, developers can make code clear and remove the errors like naming conflicts, etc. Also, the code of the self-invoking function remains hidden and can't be accessible by other parts of the code. Benefits of Using the Self-Invoking Functions 1. Avoiding the global scope 2. Initialization − The self-executing functions can be used for the initialization of variables. 3. Code privacy − Programmers can avoid accessing the code of the self-executing function by other parts of the code.

    Closures

    A closure is a function having access to the parent scope, even after the parent function has closed. The function defined in the closure ‘remembers’ the environment in which it was created. JavaScript variables can belong to the local or global scope. Global variables can be made local (private) with closures. A function can also access variables defined outside the function. In a web page, global variables belong to the page. Global variables can be used (and changed) by all other scripts in the page. A local variable can only be used inside the function where it is defined. It is hidden from other functions and other scripting code. Global and local variables with the same name are different variables. Modifying one, does not modify the other. Variable Lifetime Global variables live until the page is discarded, like when you navigate to another page or close the window. Local variables have short lives. They are created when the function is invoked, and deleted when the function is finished. A Counter Dilemma Suppose you want to use a variable for counting something, and you want this counter to be available to all functions. You could use a global variable, and a function to increase the counter: // Initiate counter let counter = 0; // Function to increment counter function add() { counter += 1; } // Call add() 3 times add(); add(); add(); // The counter should now be 3 There is a problem with the solution above: Any code on the page can change the counter, without calling add(). The counter should be local to the add() function, to prevent other code from changing it. We can remove the global counter and access the local counter by letting the function return it. JavaScript Closures use self-invoking functions: const add = (function() { let counter = 0; return function() {counter += 1; return counter} })(); add(); add(); add(); // the counter is now 3 The variable add is assigned to the return value of a self-invoking function. The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression. This way add becomes a function. The "wonderful" part is that it can access the counter in the parent scope. This is called a JavaScript closure. It makes it possible for a function to have "private" variables. The counter is protected by the scope of the anonymous function, and can only be changed using the add function. count the number of times user clicked a button on a webpage. <button onclick="updateClickCount()">click me</button> You could use a global variable, and a function to increase the counter: var counter = 0; function updateClickCount() { ++counter; // Do something with counter } But, the pitfall is that any script on the page can change the counter, without calling updateClickCount(). Now, you might be thinking of declaring the variable inside the function: function updateClickCount() { var counter = 0; ++counter; // Do something with counter } But, hey! Every time updateClickCount() function is called, the counter is set to 1 again. Thinking about nested functions? Nested functions have access to the scope "above" them. In this example, the inner function updateClickCount() has access to the counter variable in the parent function countWrapper(): function countWrapper() { var counter = 0; function updateClickCount() { ++counter; // Do something with counter } updateClickCount(); return counter; } This could have solved the counter dilemma, if you could reach the updateClickCount() function from the outside and you also need to find a way to execute counter = 0 only once not everytime. Closure to the rescue! (self-invoking function): var updateClickCount = (function(){ var counter = 0; return function(){ ++counter; // Do something with counter } })(); The self-invoking function only runs once. It sets the counter to zero (0), and returns a function expression. This way updateClickCount becomes a function. The "wonderful" part is that it can access the counter in the parent scope. This is called a JavaScript closure. It makes it possible for a function to have "private" variables. The counter is protected by the scope of the anonymous function, and can only be changed using the updateClickCount() function! A more lively example on closures var updateClickCount = (function(){ var counter = 0; return function(){ ++counter; document.getElementById("spnCount").innerHTML = counter; } })(); <button onclick="updateClickCount()">click me</button> <div> you've clicked <span id="spnCount"> 0 </span> times! </div> use closures to implement throttle and debounce functionality Throttling Throttling puts a limit on as a maximum number of times a function can be called over time. As in "execute this function at most once every 100 milliseconds." Code: const throttle = (func, limit) => { let isThrottling return function() { const args = arguments const context = this if (!isThrottling) { func.apply(context, args) isThrottling = true setTimeout(() => isThrottling = false, limit) } } } Debouncing Debouncing puts a limit on a function not be called again until a certain amount of time has passed without it being called. As in "execute this function only if 100 milliseconds have passed without it being called." Code: const debounce = (func, delay) => { let debouncing return function() { const context = this const args = arguments clearTimeout(debouncing) debouncing = setTimeout(() => func.apply(context, args), delay) } } As you can see closures helped in implementing two beautiful features which every web application should have to provide smooth UI experience functionality.

    简单JavaScript 功能


    获取操作系统详情

    window.navigator 对象包含了访客浏览器的操作系统信息。 console.log(navigator.platform);

    使用 void(0) 防止页面刷新

    当你点击一个链接时,浏览器不会加载新页面或刷新当前页面。 例如,下面的链接在不重新加载页面的情况下显示一个警告: <a href="JavaScript:void(0);" onclick="alert('Well done!')">点击我!</a>

    重定向到新页面

    在纯JavaScript中,你可以通过设置location对象的href属性来重定向用户到新页面。 function redirect() { window.location.href = "newPage.html"; } 调用redirect函数时,浏览器将导航到newPage.html。

    验证电子邮件

    每当我想验证电子邮件时,我总是寻找一个完美的代码片段。 你可能也见过在一些库中默认提供的电子邮件验证函数,例如Zod。 以下代码片段可以用完整的逻辑验证任何电子邮件: function validateEmail(email) { var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return re.test(String(email).toLowerCase()); } 如果你想要一个也接受Unicode字符的简单版本,可以使用下面的代码: function validateEmailUnicode(email) { var re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return re.test(String(email).toLowerCase()); } 这个简化版本可以匹配大多数有效的电子邮件地址,同时避免了过于复杂的正则表达式的一些缺陷。

    获取当前URL

    是的,只用JavaScript就可以做到!你可以使用window.location.href来获取和更新当前的URL。 console.log("location.href", window.location.href); // 返回完整的URL 你也可以使用document.URL来只读(不能用于导航到新URL),但这个解决方案在Firefox中有问题。 console.log("document.URL", document.URL); // 返回完整的URL(只读) 所以,通常更推荐使用window.location.href来读取和更新URL。

    使用正则表达式检测移动浏览器

    你可以使用正则表达式来判断用户是否在使用移动设备浏览。 下面的代码可以实现这一功能: window.mobilecheck = function() { var mobileCheck = false; (function(a) { if ( /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test( a ) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test( a.substr(0, 4) ) ) mobileCheck = true; })(navigator.userAgent || navigator.vendor || window.opera ); return mobileCheck; };

    不使用正则表达式检测移动浏览器

    你可以通过遍历设备列表并检查userAgent是否匹配来检测移动浏览器,这是正则表达式使用的替代方案: function detectmob() { if ( navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i) ) { return true; } else { return false; } } 这个方法看起来更清晰,更容易理解。

    检测页面上禁用的JavaScript

    你可以使用<noscript>标签来检测JavaScript是否被禁用。 <noscript>中的代码块在JavaScript被禁用时执行,通常用于在页面生成JavaScript时显示替代内容。 <script type="javascript"> // JS相关代码放这里 </script> <noscript> <a href="next_page.html?noJS=true">页面上禁用了JavaScript,请尽快启用!</a> </noscript>

    获取模块的元数据

    你可以使用import.meta对象,这是一个元属性,暴露了JavaScript模块的上下文特定元数据。 它包含了当前模块的信息,例如模块的URL。 在浏览器中,你可能会获得不同于NodeJS的元数据。 <script type="module" src="welcome-module.js"></script>; console.log(import.meta); // { url: "file:///home/user/welcome-module.js" }

    从日期获取时区偏移量

    你可以使用date对象的getTimezoneOffset方法。 该方法返回当前区域(主机系统设置)与UTC之间的时区差异,以分钟为单位。 var offset = new Date().getTimezoneOffset(); console.log(offset); // -330

    设置光标为等待状态

    可以通过使用cursor属性在JavaScript中将光标设置为等待状态。 你可以使用以下函数来实现: function myFunction() { window.document.body.style.cursor = "wait"; } 可以在页面加载时使用它。

    获取复选框的状态

    你可以在DOM中对选中的复选框应用checked属性。 如果值为true,表示复选框已选中,否则表示未选中。 例如,下面的HTML复选框元素可以使用JavaScript进行检查: <input type="checkbox" id="checkboxname" value="Agree" /> 同意条款<br /> console.log(document.getElementById('checkboxname').checked); // true or false

    为控制台消息添加CSS

    是的,你甚至可以为控制台消息应用类似于网页HTML文本的CSS样式,真的很棒: console.log( "%c 这段文字有紫色、较大的字体和白色背景", "color: purple; font-size: x-large; background: white" );

    禁用网页上的右键点击

    可以通过在body元素的oncontextmenu属性中返回false来禁用页面上的右键点击: <body oncontextmenu="return false;"></body>

    捕获浏览器后退按钮

    一开始我甚至不相信这可能。 你可以使用beforeunload事件来实现,这个事件在窗口、文档及其资源即将被卸载时触发。 此事件有助于警告用户当前数据的丢失并检测后退按钮事件。 window.addEventListener('beforeunload', () => { console.log('点击了浏览器后退按钮'); });

    分组和嵌套控制台输出

    可以使用console.group()来分组相关的日志消息,并使用console.groupEnd()关闭该组。 你还可以嵌套组,这样可以按层次结构输出消息。 例如,如果你要记录用户的详细信息: console.group("用户详情"); console.log("姓名: Sudheer Jonna"); console.log("职业: 软件开发者"); // 嵌套组 console.group("地址"); console.log("街道: Commonwealth"); console.log("城市: 洛杉矶"); console.log("州: 加利福尼亚"); // 关闭嵌套组 console.groupEnd(); // 关闭外部组 console.groupEnd(); 你还可以使用console.groupCollapsed()代替console.group(),如果你希望组默认是折叠的。

    JavaScript对象转数组的三种简单方法


    
    

    使用Object.keys()和Array.map()

    通过Object.keys()获取对象的键,然后用Array.map()把这些键对应的值提取出来。 const student = { name: '小明', age: 18, city: '北京' }; const arr = Object.keys(student).map(key => student[key]); console.log(arr); // 输出: ['小明', 18, '北京'] 在这个例子中,Object.keys(student)会返回一个包含对象所有键的数组(['name', 'age', 'city'])。 接着,Array.map()会遍历这个数组,每次迭代时,使用当前的键去获取对象中的对应值。 最终返回一个包含所有值的数组。

    使用Object.entries()

    接下来介绍的是Object.entries()方法,这是在ES6中引入的新方法。 它直接返回一个包含对象键值对的数组。 const student = { name: '小明', age: 18, city: '北京' }; const arr = Object.entries(student); console.log(arr); // 输出: [['name', '小明'], ['age', 18], ['city', '北京']] 在这个例子中,Object.entries(student)直接返回一个数组,其中每个内部数组表示对象的一个键值对。 这个方法的优势在于它能直接获取键值对,对于一些需要处理键值对的场景特别有用。

    使用Object.values()

    最后一个方法是使用Object.values(),它和Object.keys()类似,但它只返回对象的值。 这种方法特别适合当我们只关心对象的值而不需要键的时候。 const student = { name: '小明', age: 18, city: '北京' }; const arr = Object.values(student); console.log(arr); // 输出: ['小明', 18, '北京'] 在这个例子中,Object.values(student)直接返回一个包含对象所有值的数组。 这个方法的优势在于操作简单,直接获取所有值,不需要关心键。

    小结

    通过以上三种方法,我们可以轻松地将对象转换为数组。 无论是使用Object.keys()和Array.map(),Object.entries(),还是Object.values(),都各有优势,大家可以根据具体需求选择合适的方法。 如果你只需要对象的值,Object.values()是最简洁的方法。 如果你需要对象的键值对,Object.entries()是最佳选择。 如果你需要对键值进行一些处理,Object.keys()加上Array.map()会非常灵活。

    开源JavaScript流程图组件


    流程,在人类社会运作中无处不在,我们每天的上班的工作、银行的交易、做菜的过程、穿衣服的过程,万事万物都有一定的运作流程,甚至人类的生老病死都是个流程。
    软件的执行过程更是个流程,虽然在许多软件中存在依据规则的执行方法,也存在根据环境、数据等外部信息触发的事件,但是从软件全局来看,仍然是遵循着一定的业务流程,这些规则或者触发器是整体流程中功能点。
    在软件开发中流程化设计有许多应用场景,例如:低代码无代码开发、办公自动化任务编排、自动审核审批、流程化的AI Agent(类似Dify、Coze)等等。
    一些比较流行的开源流程图组件,如:flowchart.js、xyflow、GoJS、Dgrm.net等,这些组件可以以可视化的方式将流程设计器集成到Web应用中,能够大大提高系统的可用性、易用性,并且更加直观以及用户友好。
    

    flowchart.js

    https://github.com/adrai/flowchart.js flowchart.js是可以在浏览器和终端中运行的流程图DSL和SVG渲染器。 这个设计器的节点和连接是分开定义的,这样节点可以重用,连接可以快速更改。 也可以在DSL中对节点和连接样式进行更改。

    jquery.flowchart.js

    https://github.com/sdrdis/jquery.flowchart jquery.flowchart.js是一个开源的jQueryUI流程图插件。 主要功能包括: 绘制框(称为运算符)和它们之间的连接。 提供了方法,以便最终用户可以通过添加/移动/删除操作符,创建/删除它们之间的连接来编辑流程图。 开发人员可以保存/加载流程图。 操作符和链接可以使用CSS和插件参数进行自定义。 有些方法允许您添加高级功能,例如平移缩放视图或使用拖放添加操作符。

    Flowy

    https://github.com/alyssaxuu/flowy Flowy是一个可以使创建具有流程图功能的WebApps成为一项非常简单的任务。 通过在项目中实现该库,在几分钟内就可以构建自动化的思维导图工具或简单的编程平台。 其主要特征包括: 响应式拖放 自动捕捉 自动滚动 块重新排列 删除块 块自动对中 有条件捕捉 条件块删除 导入保存的文件 移动的支持 Vanilla JavaScript(无依赖)

    Dgrm.net

    https://github.com/AlexeyBoiko/DgrmJS Dgrm.net是一个纯JS的流程图编辑器。 适用于台式机,手机和平板电脑。 没有依赖性。

    Drawflow

    https://github.com/jerosoler/Drawflow Drawflow是一个开源流程设计器,可用于轻松快速地创建数据流。 主要特征包括: 可拖动节点 多个输入/输出 多个连接 删除节点和连接 添加/删除输入/输出 重新路由连接 节点上的数据同步 放大/缩小 清除数据模块 支撑模块 编辑器模式 edit、fixed或view 支持导入/导出数据 支持事件 支持移动端 Vanilla JavaScript(无依赖) 基于NPM 支持Vue组件和Nuxt

    xyflow

    https://github.com/xyflow/xyflow 这是一个强大的开源库,可以基于React或Svelte开发流程设计UI。 这个库开箱即用并且无限定制。 这里有许多这个库开发的Demo: https://reactflow.dev/showcase

    GoJS

    https://github.com/NorthwoodsSoftware/GoJS GoJS是一个可用于创建许多不同类型的交互式图表,非常灵活,支持数据可视化、绘图工具和图形编辑器等功能。 支持的图形包括:流程图、组织结构图、业务流程BPMN、泳道、时间线、状态图、看板、网络、思维导图、sankey、家谱和基因图、鱼骨图、平面图、UML、决策树、PERT图表、甘特等数百个。 GoJS包括许多内置的布局,包括:树布局、热力图、圆形和分层有向图布局,也支持自定义布局。 GoJS以Canvas元素呈现在HTML 上(导出为SVG或图像格式)或直接作为SVG DOM。 GoJS可以在Web浏览器中运行,也可以在Node或Puppeteer中运行。 GoJS图由模型支持,通常通过JSON格式的文本保存和加载。 在下面URL里可以看到GoJS 各种各样的Demo: https://gojs.net/latest/samples/index.html

    React Diagrams

    https://github.com/projectstorm/react-diagrams React Diagrams是一个用React写的非常精简的工作流图形库。

    Flowchart React

    https://github.com/joyceworks/flowchart-react 这是一个适用于React.js的免费开源的轻量级流程图设计器。

    React Flow Chart

    https://github.com/MrBlenny/react-flow-chart React Flow Chart是一个免费开源的、灵活的、无状态的、声明式的React流程图库。

    REAFLOW

    https://github.com/reaviz/reaflow REAFLOW是一个用于构建静态或交互式编辑器的模块化图表引擎。 该库功能丰富且模块化,允许显示具有完全可定制性的复杂可视化。

    React Flow Chart Editor

    https://github.com/aislelabs/react-flowchart-editor 这个开源流程图编辑器支持窗口定位、缩放和工作区平移。 简单的组件插件架构,允许轻松定制。 没有额外的包依赖。

    React Flowchart Builder

    https://github.com/TaqBostan/react-flowchart-builder 这是一个免费的轻量级流程图组件。 其特征包括: 支持不同形状的节点。 支持添加/删除/移动节点 支持添加/删除/重塑节点之间的链接 支持启用/禁用添加/编辑/删除链接 支持缩放和平移 原始或键入的输入/输出

    X-Flowchart-Vue

    https://github.com/OXOYO/X-Flowchart-Vue 一个基于G6和Vue的可视化图形编辑器。

    Node.js File System Module


    Node.js as a File Server

    The Node.js file system module allows you to work with the file system on your computer. To include the File System module, use the require() method: var fs = require('fs'); Common use for the File System module: Read files Create files Update files Delete files Rename files

    Read Files

    The fs.readFile() method is used to read files on your computer. Assume we have the following HTML file (located in the same folder as Node.js): demofile1.html <html> <body> <h1>My Header</h1> <p>My paragraph.</p> </body> </html> Create a Node.js file that reads the HTML file, and return the content:

     Example Get your own Node.js Server

    var http = require('http'); var fs = require('fs'); http.createServer(function (req, res) { fs.readFile('demofile1.html', function(err, data) { res.writeHead(200, {'Content-Type': 'text/html'}); res.write(data); return res.end(); }); }).listen(8080); Save the code above in a file called "demo_readfile.js", and initiate the file: Initiate demo_readfile.js: C:\Users\Your Name>node demo_readfile.js If you have followed the same steps on your computer, you will see the same result as the example: http://localhost:8080

    Create Files

    The File System module has methods for creating new files: fs.appendFile() fs.open() fs.writeFile() The fs.appendFile() method appends specified content to a file. If the file does not exist, the file will be created:

     Example

    Create a new file using the appendFile() method: var fs = require('fs'); fs.appendFile('mynewfile1.txt', 'Hello content!', function(err) { if (err) throw err; console.log('Saved!'); }); The fs.open() method takes a "flag" as the second argument, if the flag is "w" for "writing", the specified file is opened for writing. If the file does not exist, an empty file is created:

     Example

    Create a new, empty file using the open() method: var fs = require('fs'); fs.open('mynewfile2.txt', 'w', function(err, file) { if (err) throw err; console.log('Saved!'); }); The fs.writeFile() method replaces the specified file and content if it exists. If the file does not exist, a new file, containing the specified content, will be created:

     Example

    Create a new file using the writeFile() method: var fs = require('fs'); fs.writeFile('mynewfile3.txt', 'Hello content!', function(err) { if (err) throw err; console.log('Saved!'); });

    Update Files

    The File System module has methods for updating files: fs.appendFile() fs.writeFile() The fs.appendFile() method appends the specified content at the end of the specified file:

     Example

    Append "This is my text." to the end of the file "mynewfile1.txt": var fs = require('fs'); fs.appendFile('mynewfile1.txt', ' This is my text.', function(err) { if (err) throw err; console.log('Updated!'); }); The fs.writeFile() method replaces the specified file and content:

     Example

    Replace the content of the file "mynewfile3.txt": var fs = require('fs'); fs.writeFile('mynewfile3.txt', 'This is my text', function(err) { if (err) throw err; console.log('Replaced!'); });

    Delete Files

    To delete a file with the File System module, use the fs.unlink() method. The fs.unlink() method deletes the specified file:

     Example

    Delete "mynewfile2.txt": var fs = require('fs'); fs.unlink('mynewfile2.txt', function(err) { if (err) throw err; console.log('File deleted!'); });

    Rename Files

    To rename a file with the File System module, use the fs.rename() method. The fs.rename() method renames the specified file:

     Example

    Rename "mynewfile1.txt" to "myrenamedfile.txt": var fs = require('fs'); fs.rename('mynewfile1.txt', 'myrenamedfile.txt', function(err) { if (err) throw err; console.log('File Renamed!'); });

    Upload Files

    You can also use Node.js to upload files to your computer.

    get commands and perform your action in the callback

    import os from "os"; setInterval(function() { console.log("Process running"); }, 3000); process.stdin.setEncoding("utf8"); process.stdin.on("readable", function() { const chunk = process.stdin.read() as string; chunk .split(os.EOL) .forEach(str => { if (str === null || !str.length) { return; } console.log("data: " + str); }); });

    Node.js formatted console output

    Examples from the mdn page: 'abc'.padStart(10); // " abc" 'abc'.padStart(10, "foo"); // "foofoofabc" 'abc'.padStart(6,"123465"); // "123abc" 'abc'.padStart(8, "0"); // "00000abc" 'abc'.padStart(1); // "abc" 'abc'.padEnd(10); // "abc " 'abc'.padEnd(10, "foo"); // "abcfoofoof" 'abc'.padEnd(6, "123456"); // "abc123" 'abc'.padEnd(1); // "abc" For indenting a json onto the console try using JSON.stringify. The third parameter provides the indention required. JSON.stringify({ a:1, b:2, c:3 }, null, 4); // { // "a": 1, // "b": 2, // "c": 3 // }

    The debugger Keyword

    The debugger keyword stops the execution of JavaScript, and calls (if available) the debugging function. This has the same function as setting a breakpoint in the debugger. If no debugging is available, the debugger statement has no effect. With the debugger turned on, this code will stop executing before it executes the third line. Example let x = 15 * 5; debugger; document.getElementById("demo").innerHTML = x;

    Javascript脚本延迟加载的方式



    js的延迟加载方法 (js的延迟加载有助于提高页面的加载速度) 程序性能是项目完成后需要长期做的一件事情,让用户的体验更好,性能优化的核心思想就是快,可以预先准备数据(如缓存的使用),可以按需获取,可以分段获取等都是常见的优化手段。

    defer属性

    <!DOCTYPE html> <html> <head> <script src="test1.js" defer="defer"></script> <script src="test2.js" defer="defer"></script> </head> <body> <!-- 这里放内容 --> </body> </html> 用途: 让脚本在执行时不会影响页面的构造。 也就是说,脚本会被延迟到整个页面都解析完毕之后再执行说明:虽然<script>元素放在了<head>元素中,但包含的脚本将延迟浏览器遇到</html>标签后再执行。 当浏览器解析到 script 脚本,有 defer 时,浏览器会并行下载有 defer 属性的 script,而不会阻塞页面后续处理。 所有的 defer 脚本保证是按顺序依次执行的。 (但实际上延迟脚本并不一定会按照顺序执行,因此最好只包含一个延迟脚本) defer 属性只适用于外部脚本文件。

    async属性

    用途: 不让页面等待脚本下载和执行,从而异步加载页面其他内容。 <!DOCTYPE html> <html> <head> <script src="test1.js" async></script> <script src="test2.js" async></script> </head> <body> <!-- 这里放内容 --> </body> </html> async属性是HTML5新增的。 作用和defer类似,但是它将在下载后尽快执行,不能保证脚本会按顺序执行。 它们将在onload 事件之前完成。 Firefox3.6、Opera 10.5、IE 9和 最新的Chrome 和 Safari 都支持 async 属性。 可以同时使用 async 和 defer,这样IE 4之后的所有IE 都支持异步加载。 浏览器会立即下载脚本,但不妨碍页面中的其他操作,比如下载其他资源或等待加载其他脚本。 加载和渲染后续文档元素的过程和 main.js 的加载与执行并行进行,这个过程是异步的。 它们将在 onload 事件之前完成。 说明:浏览器会立即下载脚本,但不妨碍页面中的其他操作,加载和渲染后续文档元素的过程和脚本的加载与执行并行进行。 这个过程是异步的,它们将在 onload 事件之前完成。 所有的 defer 脚本不能控制加载的顺序。 。 asyncr 属性只适用于外部脚本文件。

    动态创建DOM方式 (使用的最多)

    <script type="text/javascript"> function downloadJSAtOnload() { var element = document.createElement("script"); element.src = "defer.js"; document.body.appendChild(element); } if (window.addEventListener) //添加监听事件 window.addEventListener("load",downloadJSAtOnload, false); //事件在冒泡阶段执行 else if (window.attachEvent) window.attachEvent("onload",downloadJSAtOnload); else window.onload = downloadJSAtOnload; </script> PS:这里插一句addEventListener() 也是常考的知识点之一:addEventListener() 方法用于向指定元素添加事件句柄。 使用 removeEventListener() 方法来移除 addEventListener() 方法添加的事件句柄。 语法: element.addEventListener(event, function, useCapture) event (必须)字符串,指定事件名。 注意: 不要使用 “on” 前缀。 例如,使用 “click” ,而不是使用 “onclick”。 function (必须)指定要事件触发时执行的函数。 当事件对象会作为第一个参数传入函数。 事件对象的类型取决于特定的事件。 例如, “click” 事件属于 MouseEvent(鼠标事件) 对象。 useCapture (可选)布尔值,指定事件是否在捕获或冒泡阶段执行。 【true:事件句柄在捕获阶段执行;false:默认,事件句柄在冒泡阶段执行】 <p>该实例使用 addEventListener() 方法来向按钮添加点击事件。 </p> <button>点我</button> <p></p> <script> document.getElementById("myBtn").addEventListener("click", function(){ document.getElementById("demo").innerHTML = "Hello World"; }); </script> 效果如图:

    使用Jquery的getScript()方法

    $.getScript("outer.js",function(){//回调函数,成功获取文件后执行的函数 console.log("脚本加载完成") }); url(必写):将要请求的 URL 字符串 success(response,status)(可选):规定请求成功后执行的回调函数。 其中的参数 response - 包含来自请求的结果数据 status - 包含请求的状态("success", "notmodified", "error", "timeout" 或 "parsererror") 用途: 通过 HTTP GET 请求载入并执行 JavaScript 文件。 //加载并执行 test.js: $.getScript("test.js"); //加载并执行 test.js ,成功后显示信息 $.getScript("test.js", function(){ alert("Script loaded and executed."); });

    使用setTimeout延迟方法的加载时间

    延迟加载js代码,给网页加载留出时间 <script type="text/javascript"> function A(){ $.post("/lord/login",{name:username,pwd:password},function(){ alert("Hello World!"); }) } $(function(){ setTimeout("A()",1000); //延迟1秒 }) </script>

    让js最后加载

    例如引入外部js脚本文件时,如果放入html的head中,则页面加载前该js脚本就会被加载入页面,而放入body中,则会按照页面从上倒下的加载顺序来运行javascript的代码,从而阻止浏览器后续操作~~~ 所以我们可以把js外部引入的文件放到页面底部,来让js最后引入,从而加快页面加载速度。 上述方法5,6也会偶尔让你收到Google页面速度测试工具的“延迟加载javascript”警告。 所以这里的解决方案将是来自Google帮助页面的推荐方案。 浏览器渲染的原理(1)浏览器向服务器请求到了HTML文档,然后开始解析,生成DOM(文档对象模型),到这里为止,HTML文档被加载、解析完成,如果有css则生成CSSOM(css对象模型),然后DOM和CSSOM生成渲染树,有了渲染树就知道了所有节点的样式,然后根据节点和样式计算它们在浏览器的大小和位置,然后就是绘制到浏览器(2)其中存在一个问题:JavaScript可以阻塞DOM的生成··如果在HTML中插入一个脚本,浏览器是默认先执行脚本再继续往下解析HTML,而JavaScript是可以查询任意对象的样式,所以需要CSSOM生成才可以执行JavaScript。 ··其中存在同步脚本和异步脚本的区别:·同步脚本:停止解析,先执行脚本再继续往下解析·异步脚本:H5中<script>定义了defer 和 async 属性 //这些代码应被放置在</body>标签前(接近HTML文件底部) <script type="text/javascript"> function downloadJSAtOnload() { var element = document.createElement("script"); element.src = "defer.js"; document.body.appendChild(element); } if (window.addEventListener) window.addEventListener("load", downloadJSAtOnload, false); else if (window.attachEvent) window.attachEvent("onload", downloadJSAtOnload); else window.onload = downloadJSAtOnload; </script> 这段代码意思是等到整个文档加载完后,再加载外部文件“defer.js”。 使用此段代码的步骤:复制上面代码 粘贴代码到HTML的标签前 (靠近HTML文件底部) 修改“defer.js”为你的外部JS文件名 确保你文件路径是正确的。 例如:如果你仅输入“defer.js”,那么“defer.js”文件一定与HTML文件在同一文件夹下。 注意:这段代码直到文档加载完才会加载指定的外部js文件。 因此,不应该把那些页面正常加载需要依赖的javascript代码放在这里。 而应该将JavaScript代码分成两组。 一组是因页面需要而立即加载的javascript代码,另外一组是在页面加载后进行操作的javascript代码(例如添加click事件或其他东西)。 这些需等到页面加载后再执行的JavaScript代码,应放在一个外部文件,然后再引进来。

    实战- 图片懒加载

    原理: 一张图片就是一个<img>标签,浏览器是否发起请求图片是根据<img>的 src 属性,所以实现懒加载的关键就是,在图片没有进入可视区域时,先不给<img>的 src 赋值,这样浏览器就不会发送请求了,等到图片进入可视区域再给 src 赋值。 <img class="lazy" src="img/loading.gif" lazy-src="img/pic1.jpg" > <img class="lazy" src="img/loading.gif" lazy-src="img/pic2.jpg" > function lazyload(){ var visible; $('img').each(function() { if( typeof($(this).attr("lazy-src"))!="undefined" ){ // 判断图片是否需要懒加载 visible = $(this).offset().top - $(window).scrollTop(); //图片距离顶部的距离 if ((visible > 0) && (visible < $(window).height())) {// 判断图片是否在可视区域 visible = true;// 图片在可视区域 } else { visible = false;// 图片不在可视区域 } if (visible) { $(this).attr('src', $(this).attr('lazy-src')); } } }); } // 打开页面触发函数 lazyload(); // 滚屏时触发函数 window.onscroll =function(){ lazyload(imgs); }

    获取单选按钮组的值

    比如注册时选择性别、问卷调查时选择答案等。 使用一组单选按钮来表示性别选项。 <div> <input type="radio" id="genderm" name="gender" value="male" /> <label for="genderm">男</label> <input type="radio" id="genderf" name="gender" value="female" checked /> <label for="genderf">女</label> </div> 默认情况下,选中了“女”。 可以使用document.querySelector方法来获取被选中的单选按钮,然后通过它的value属性来获取对应的值。 const selectedGender = document.querySelector('input[name="gender"]:checked').value; console.log(selectedGender); // 输出: "female" 解释: document.querySelector('input[name="gender"]:checked'):这段代码会返回被选中的name属性为“gender”的单选按钮元素。 .value:通过value属性获取该单选按钮的值。 所以,当我们运行这段代码时,selectedGender的值会是“female”,因为默认情况下“女”按钮是选中的。

    autofit.js 大屏自适应

    autofit.js 是一个可以让你的PC项目自适应屏幕的工具,其原理非常简单,即在scale等比缩放的基础上,向右或向下增加了宽度或高度,以达到充满全屏的效果,使用autofit.js不会挤压、拉伸元素,它只是单纯的设置了容器的宽高。

    示例效果图

    示例1

    引入

    示例2 import autofit from'autofit.js' // 快速开始 autofit.init() // 使用 exportdefault{ mounted(){ autofit.init({ designHeight:1080, designWidth:1920, renderDom:"#app", resize:true },false)// 可关闭控制台运行提示输出 }, }
    以上使用的是默认参数,可根据实际情况调整,参数分别为• renderDom(可选):渲染的dom,默认是 "#app",必须使用id选择器 • designWidth(可选):设计稿的宽度,默认是 1920 • designHeight(可选):设计稿的高度,默认是 929 ,如果项目以全屏展示,则可以设置为1080 • resize(可选):是否监听resize事件,默认是 true

    忽略某些元素

    autofit.init({ ignore:[ { dom:".gaodeMap", }, ] }) // 传入 ignore 以使元素不被缩放 // 更个性化的设置: autofit.init({ ignore:[ { dom:".gaodeMap",//必填 height:300,//可选,写数字即可(px) width:300,//可选,写数字即可(px) scale:1.2,//可选:回放程度,基于主元素缩放后的大小 fontSize:26//可选,如果自定义缩放后文字大小不合适,可以在这里设置文字大小 }, { //... } ] })

    原生项目或jquery项目引入方式

    将准备好的包放在项目中,常规引入方式 <script src="assets/autofit/autofit.js"></script> 需要修改autoofit.js文件,将//export { elRectification }; //export default autofit;注释掉,不然报错,当然如果你项目支持import方式可以不用注释掉; 在你的项目js中使用autofit.init()

    鼠标移动高亮边框效果

    一、过程分析

    效果: 在Windows系统里有一个很棒的细节效果,元素的渐变高亮边框是可以感知鼠标的,边框的高亮部分会跟随鼠标的移动而移动。 这种效果也是比较常见的,但是实现起来还是需要一点时间和思路的。 首先,我们先完成基础的布局。 代码如下: <div class="container"> <div class="card"> <div class="inner"> <p>黄鹤楼送孟浩然之广陵</p> <p>唐 · 李白</p> <p>故人西辞黄鹤楼,烟花三月下扬州。 </p> <p>孤帆远影碧空尽,唯见长江天际流。 </p> </div> </div> <div class="card"> <div class="inner"> <p>送元二使安西</p> <p>唐 · 王维</p> <p>渭城朝雨浥轻尘,客舍青青柳色新。 </p> <p>劝君更尽一杯酒,西出阳关无故人。 </p> </div> </div> <div class="card"> <div class="inner"> <p>春日</p> <p>宋 · 朱熹</p> <p>胜日寻芳泗水滨,无边光景一时新。 </p> <p>等闲识得东风面,万紫千红总是春。 </p> </div> </div> <div class="card"> <div class="inner"> <p>小池</p> <p>唐 · 杨万里</p> <p>泉眼无声惜细流,树阴照水爱晴柔。 </p> <p>小荷才露尖尖角,早有蜻蜓立上头。 </p> </div> </div> <div class="card"> <div class="inner"> <p>村居</p> <p>清 · 高鼎</p> <p>草长莺飞二月天,拂堤杨柳醉春烟。 </p> <p>儿童散学归来早,忙趁东风放纸鸢。 </p> </div> </div> <div class="card"> <div class="inner"> <p>晓出净慈寺送林子方</p> <p>唐 · 杨万里</p> <p>毕竟西湖六月中,风光不与四时同。 </p> <p>接天莲叶无穷碧,映日荷花别样红。 </p> </div> </div> </div> body { background-color: black; } p { margin: 0; line-height: 2; } .container { display: grid; width: 100%; margin-top: 2rem; color: #f0f0f0; grid-template-columns: repeat(3, 1fr); gap: 20px; text-align: center; } .card { aspect-ratio: 4/2; border-radius: 8px; background-color: rgba(255, 255, 255, 0.2); } .inner { background: #222; display: flex; flex-direction: column; align-items: center; justify-content: center; } 接下来给 .card 加上相对定位position: relative属性,给 .inner 加上绝对定位position: absolute属性,让card盒子和inner盒子完全重叠在一起。 .card { aspect-ratio: 4/2; border-radius: 8px; background-color: rgba(255, 255, 255, 0.2); position: relative; } .inner { position: absolute; inset: 10px; background: #222; display: flex; flex-direction: column; align-items: center; justify-content: center; } 为了方便观察,给 .inner 设置 inset: 10px 属性,此属性相当于 left: 10px;top: 10px;right: 10px; bottom: 10px;。 效果如下: 想要实现高亮的效果,我们还需要在 .card 和 .inner 之间再插入一层,这一层是我们实现高亮的关键!这三层盒子一样大小。 .card::before { content: ""; position: absolute; inset: 0; background: radial-gradient(closest-side circle, #fff, transparent); } .inner { position: absolute; inset: 10px; /* background: #222; */ display: flex; flex-direction: column; align-items: center; justify-content: center; } 为了便于观察,先把.inner的背景色去掉。 效果如下: 看到这里有的人可能已经知道这个中间层用来干什么的了。 没错,这不就是一个渐变高亮的效果嘛!我们再在 .card::before 加上一个 transform属性,同时在 .card 上加上 overflow: hidden属性,观察浏览器,神奇的效果出现了!我悟了! .card { aspect-ratio: 4/2; border-radius: 8px; background-color: rgba(255, 255, 255, 0.2); position: relative; overflow: hidden; } .card::before { content: ""; position: absolute; inset: 0; background: radial-gradient(closest-side circle, #fff, transparent); transform: translate(70px, 80px); } .inner { position: absolute; inset: 10px; background: #222; display: flex; flex-direction: column; align-items: center; justify-content: center; } 效果如下: 原来如此,一个渐变高亮的边框效果不就实现了嘛! 接下来就是用js代码实现 .card::before 中间层跟随鼠标移动即可。 假如图中的小圆圈为鼠标位置,当鼠标移动到此位置时,只需要计算把每张卡片中间层的中心偏移到鼠标的位置即可。 那怎么去计算呢? 首先,获取到每张卡片的元素,监听鼠标移动onmousemove事件,鼠标移动时循环遍历每个卡片元素给每个卡片设置transform: translate(x, y)即可。 x(偏移的水平距离) = 鼠标离视口的水平距离 - 元素离视口的水平距离 - 元素宽度的一半。 y(偏移的垂直距离) = 鼠标离视口的垂直距离 - 元素离视口的垂直距离 - 元素高度的一半。 代码如下: const container = document.querySelector('.container'); const cards = document.querySelectorAll('.card'); container.onmousemove = e => { for(const card of cards) { const rect = card.getBoundingClientRect(); const x = e.clientX - rect.left - rect.width / 2; const y = e.clientY - rect.top - rect.height / 2; card.style.setProperty('--x', `${x}px`); card.style.setProperty('--y', `${y}px`); } }

    二、完整代码

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>b.html</title> <style type="text/css"> body { background-color: black; } p { margin: 0; line-height: 2; } .container { display: grid; width: 90%; margin: 2rem auto 0; color: #f0f0f0; grid-template-columns: repeat(3, 1fr); gap: 20px; text-align: center; } .card { aspect-ratio: 4/2; border-radius: 8px; background-color: rgba(255, 255, 255, 0.2); position: relative; overflow: hidden; } .card::before { content: ""; position: absolute; inset: 0; background: radial-gradient(closest-side circle, #fff, transparent); /* 偏移到看不到的地方 */ transform: translate(var(--x, -10000px), var(--y, -10000px)); } .inner { position: absolute; inset: 10px; background: #222; display: flex; flex-direction: column; align-items: center; justify-content: center; } </style> </head> <body> <div class="container"> <div class="card"> <div class="inner"> <p>黄鹤楼送孟浩然之广陵</p> <p>唐 · 李白</p> <p>故人西辞黄鹤楼,烟花三月下扬州。 </p> <p>孤帆远影碧空尽,唯见长江天际流。 </p> </div> </div> <div class="card"> <div class="inner"> <p>送元二使安西</p> <p>唐 · 王维</p> <p>渭城朝雨浥轻尘,客舍青青柳色新。 </p> <p>劝君更尽一杯酒,西出阳关无故人。 </p> </div> </div> <div class="card"> <div class="inner"> <p>春日</p> <p>宋 · 朱熹</p> <p>胜日寻芳泗水滨,无边光景一时新。 </p> <p>等闲识得东风面,万紫千红总是春。 </p> </div> </div> <div class="card"> <div class="inner"> <p>小池</p> <p>唐 · 杨万里</p> <p>泉眼无声惜细流,树阴照水爱晴柔。 </p> <p>小荷才露尖尖角,早有蜻蜓立上头。 </p> </div> </div> <div class="card"> <div class="inner"> <p>村居</p> <p>清 · 高鼎</p> <p>草长莺飞二月天,拂堤杨柳醉春烟。 </p> <p>儿童散学归来早,忙趁东风放纸鸢。 </p> </div> </div> <div class="card"> <div class="inner"> <p>晓出净慈寺送林子方</p> <p>唐 · 杨万里</p> <p>毕竟西湖六月中,风光不与四时同。 </p> <p>接天莲叶无穷碧,映日荷花别样红。 </p> </div> </div> </div> </body> <script type="text/javascript"> const container = document.querySelector('.container'); const cards = document.querySelectorAll('.card'); container.onmousemove = e => { for(const card of cards) { const rect = card.getBoundingClientRect(); const x = e.clientX - rect.left - rect.width / 2; const y = e.clientY - rect.top - rect.height / 2; card.style.setProperty('--x', `${x}px`); card.style.setProperty('--y', `${y}px`); } } </script> </html>

    自定义实用JavaScript 函数

    练习一:折扣计算器

     场景描述

    在快节奏的商业世界中,快速高效地计算折扣至关重要。 想象一下,你正在管理一家在线商店,价格和折扣不断变化。 在这种情况下,自动化折扣计算不仅方便,而且必要。 这正是 JavaScript 函数大显身手的地方。

     练习代码

    function getDiscountedPrice(originalPrice, discountRate) { let discount = (originalPrice * discountRate) / 100; return originalPrice - discount; } // 示例函数调用 let initialPrice = 200; // 商品的原价 let discountPercentage = 15; // 折扣百分比 (15%) // 计算折后价格 let finalPrice = getDiscountedPrice(initialPrice, discountPercentage); // 打印结果 console.log("原价: ¥" + initialPrice + ", 折后价: ¥" + finalPrice);

     详细说明

    getDiscountedPrice 函数设计用于接受两个参数:商品的原价(originalPrice)和折扣百分比(discountRate)。 let discount = (originalPrice * discountRate) / 100; 计算实际的折扣金额。 例如,若商品价格为200元,折扣为15%,则折扣金额为30元。 originalPrice - discount 从原价中减去折扣金额,得到折后的最终价格。 在示例中,我们定义了两个变量,initialPrice 和 discountPercentage,分别表示商品的原价和折扣百分比。 然后调用 getDiscountedPrice 函数并传入这些值,计算出的折后价格存储在 finalPrice 变量中。 最后,我们使用 console.log 输出原价和折后价,清晰地展示了函数的计算结果。

     实际应用

    这个函数可以有效地应用于各种场景,例如: 电子商务:在促销或活动期间更新商品价格。 库存管理应用:快速计算库存商品的折后价格。 POS(销售点)系统:在实体店结账时应用折扣。 在每种情况下,getDiscountedPrice 函数都简化了定价过程,减少了人工错误,提高了操作效率。 将此函数集成到网页应用或管理系统中,确保快速准确地计算折扣价格,从而改善客户的购物体验和商家的数据管理。

     代码分析

    function getDiscountedPrice(originalPrice, discountRate) { let discount = (originalPrice * discountRate) / 100; return originalPrice - discount; } 函数定义: function getDiscountedPrice:这里定义了一个名为 getDiscountedPrice 的函数。 (originalPrice, discountRate):函数接受两个参数——originalPrice 是商品的原价,discountRate 是折扣百分比。 返回语句: let discount = (originalPrice * discountRate) / 100;:函数计算折扣金额,即用商品原价乘以折扣百分比再除以100,将结果存储在 discount 变量中。 return originalPrice - discount;:从原价中减去折扣金额,得到最终的折后价格。

     函数调用和结果

    let initialPrice = 200; // 商品的原价 let discountPercentage = 15; // 折扣百分比 (15%) let finalPrice = getDiscountedPrice(initialPrice, discountPercentage); console.log("原价: ¥" + initialPrice + ", 折后价: ¥" + finalPrice); 设置变量: let initialPrice = 200;:声明一个变量 initialPrice,初始化为200,表示商品的原价。 let discountPercentage = 15;:类似地,将 discountPercentage 设置为15,表示15%的折扣。 计算折后价格: let finalPrice = getDiscountedPrice(initialPrice, discountPercentage);:调用 getDiscountedPrice 函数,传入 initialPrice 和 discountPercentage 作为参数。 计算结果,即折后价格,存储在 finalPrice 变量中。 打印结果: console.log("原价: ¥" + initialPrice + ", 折后价: ¥" + finalPrice);:最后,我们打印出原价和折后价格,展示函数在计算折扣价格方面的有效性。

    练习二:年龄验证

     场景描述

    年龄验证在在线零售、数字内容平台和年龄限制服务等多个领域中都是至关重要的一环。 确保用户或客户符合年龄要求不仅是法律合规问题,更是一种社会责任。 在这些情况下,使用 JavaScript 进行自动化的年龄验证系统可以提高检查的效率和准确性。

     练习代码

    function checkAge(age) { return age >= 18 ? "成年" : "未成年"; } // 示例函数调用 let userAge = 21; // 用户年龄 let result = checkAge(userAge); // 输出结果 console.log("用户是: " + result);

     详细说明

    checkAge 函数接受一个参数 age,表示用户的年龄。 return age >= 18 ? "成年" : "未成年"; 使用三元运算符来检查年龄是否大于或等于 18。 如果条件为真,返回 "成年";否则返回 "未成年"。 在示例中,我们定义了一个变量 userAge,代表用户的年龄。 然后调用 checkAge 函数并传入这个值,函数的返回结果存储在 result 变量中。 最后,我们使用 console.log 输出验证结果,展示用户是否为成年人。

     实际应用

    这个函数可以有效地应用于各种场景,例如: 在线零售和电子商务:限制购买酒类或烟草等年龄限制商品。 数字内容平台:控制访问特定评级的电影或电子游戏等年龄限制内容。 年龄限制服务:验证用户是否符合租车等服务的最低年龄要求。 在这些应用中,checkAge 函数可以集成到用户注册或结账流程中,自动判断用户是否符合年龄要求。 此自动化过程不仅简化了操作,还帮助遵守法律法规和道德标准。

     代码分析

    function checkAge(age) { return age >= 18 ? "成年" : "未成年"; } 函数定义: function checkAge:定义了一个名为 checkAge 的新函数。 (age):函数接受一个参数 age,表示要验证年龄的用户年龄。 返回语句: return age >= 18 ? "成年" : "未成年";:这是函数的核心逻辑,使用三元运算符实现。 三元运算符是一种简洁的条件语句写法,它检查一个条件,并在条件为真时返回一个值,条件为假时返回另一个值。 age >= 18:此条件检查年龄是否大于或等于 18。 "成年" : "未成年":如果条件为真(年龄大于或等于 18),函数返回 "成年";如果条件为假(年龄小于 18),函数返回 "未成年"。

     函数调用和结果

    let userAge = 21; // 用户年龄 let result = checkAge(userAge); console.log("用户是: " + result); 变量初始化和函数调用: let userAge = 21;:声明一个变量 userAge,值为 21,表示用户的年龄。 let result = checkAge(userAge);:调用 checkAge 函数,传入 userAge 作为参数。 函数返回值("成年" 或 "未成年")存储在 result 变量中。 输出结果: console.log("用户是: " + result);:最后,打印出验证结果。 在本例中,由于 userAge 是 21,输出将是 "用户是: 成年"。

    练习三:温度转换器

     场景描述

    温度转换在天气预报、烹饪等多个领域都是一个常见需求。 不同的地区和行业可能使用不同的温度计量单位,因此编写一个可以在摄氏度和华氏度之间转换温度的函数非常实用。 这个函数可以帮助标准化全球应用、科学研究和日常生活中的温度数据。

     练习代码

    function convertCelsiusToFahrenheit(celsiusTemp) { return (celsiusTemp * 1.8) + 32; } // 示例函数调用 let currentTempInCelsius = 25; // 摄氏温度 let tempInFahrenheit = convertCelsiusToFahrenheit(currentTempInCelsius); // 输出结果 console.log(currentTempInCelsius + "°C 等于 " + tempInFahrenheit + "°F");

     详细说明

    convertCelsiusToFahrenheit 函数接受一个参数 celsiusTemp,表示需要转换的摄氏温度。 return (celsiusTemp * 1.8) + 32; 是转换公式。 该公式首先将摄氏温度乘以 1.8,然后加上 32,转换为华氏温度。 函数返回转换后的华氏温度。 在示例中,我们定义了一个变量 currentTempInCelsius,表示当前的摄氏温度。 然后调用 convertCelsiusToFahrenheit 函数并传入这个值,函数返回的华氏温度存储在 tempInFahrenheit 变量中。 最后,我们使用 console.log 输出结果,展示温度转换的效果。

     实际应用

    这个函数可以有效地应用于各种场景,例如: 天气预报:在国际天气报告中转换不同国家使用的温度计量单位。 烹饪和烘焙:食谱通常使用摄氏度或华氏度,用户可以根据自己的偏好或当地标准进行转换。 科学研究:在涉及国际合作的科学研究中,温度数据可能需要转换以确保一致性和理解。 这个函数简化了温度转换的过程,使其成为在任何需要统一或标准化温度数据的场景中非常有价值的工具。

     代码分析

    function convertCelsiusToFahrenheit(celsiusTemp) { return (celsiusTemp * 1.8) + 32; } 函数定义: function convertCelsiusToFahrenheit:定义了一个名为 convertCelsiusToFahrenheit 的新函数。 (celsiusTemp):函数接受一个参数 celsiusTemp,表示需要转换为华氏度的摄氏温度。 返回语句和转换公式: return (celsiusTemp * 1.8) + 32;:这是将摄氏度转换为华氏度的公式。 函数将摄氏温度乘以 1.8,然后加上 32。

     函数调用和结果

    let currentTempInCelsius = 25; // 摄氏温度 let tempInFahrenheit = convertCelsiusToFahrenheit(currentTempInCelsius); console.log(currentTempInCelsius + "°C 等于 " + tempInFahrenheit + "°F"); 变量初始化和函数调用: let currentTempInCelsius = 25;:声明一个变量 currentTempInCelsius,值为 25,表示摄氏温度。 let tempInFahrenheit = convertCelsiusToFahrenheit(currentTempInCelsius);:调用 convertCelsiusToFahrenheit 函数,传入 currentTempInCelsius 作为参数。 函数返回值(华氏温度)存储在 tempInFahrenheit 变量中。 输出结果: console.log(currentTempInCelsius + "°C 等于 " + tempInFahrenheit + "°F");:最后,打印出转换结果。 在本例中,由于 currentTempInCelsius 为 25,输出将是 "25°C 等于 77°F"。

    练习四:圆面积计算器

     场景描述

    计算圆的面积是数学、工程和设计等多个领域中的基础任务。 无论是设计一个圆形花园,计算圆桌所需的材料,还是解决几何问题,快速准确地确定圆的面积都是非常有价值的。 在这些场景中,使用 JavaScript 函数来进行此计算可以节省时间并减少错误。

     练习代码

    function getCircleArea(radius) { return Math.PI * Math.pow(radius, 2); } // 示例函数调用 let circleRadius = 7; // 圆的半径 let area = getCircleArea(circleRadius); // 输出结果 console.log("圆的面积是: " + area + " 平方单位");

     详细说明

    getCircleArea 函数接受一个参数 radius,表示需要计算面积的圆的半径。 return Math.PI * Math.pow(radius, 2); 是计算面积的公式。 该公式将半径的平方乘以圆周率 π(π是数学常数,Math.PI 是 JavaScript 内置属性)。 函数返回圆的面积,单位为平方单位。 在示例中,我们定义了一个变量 circleRadius,表示圆的半径。 然后调用 getCircleArea 函数并传入这个值,函数返回的面积存储在 area 变量中。 最后,我们使用 console.log 输出结果,展示圆的面积计算效果。

     实际应用

    这个函数可以有效地应用于各种场景,例如: 数学和教育:帮助学生和教育者解决几何问题。 工程项目:计算施工和制造中的圆形部件的尺寸。 设计和艺术:帮助艺术家和设计师确定他们作品中圆形元素的面积,例如平面设计或建筑图纸。 这个函数 getCircleArea 简化了计算圆面积的过程,使其成为专业人士和学生在各种需要计算圆面积的场景中的便捷工具。

     代码分析

    function getCircleArea(radius) { return Math.PI * Math.pow(radius, 2); } 函数定义: function getCircleArea:定义了一个名为 getCircleArea 的新函数。 (radius):函数接受一个参数 radius,表示需要计算面积的圆的半径。 返回语句和面积计算公式: return Math.PI * Math.pow(radius, 2);:这是计算圆面积的公式。 函数将 Math.PI(数学常数 π)乘以半径的平方(Math.pow(radius, 2))。

     函数调用和结果

    let circleRadius = 7; // 圆的半径 let area = getCircleArea(circleRadius); console.log("圆的面积是: " + area + " 平方单位"); 变量初始化和函数调用: let circleRadius = 7;:声明一个变量 circleRadius,值为 7,表示圆的半径。 let area = getCircleArea(circleRadius);:调用 getCircleArea 函数,传入 circleRadius 作为参数。 函数返回值(圆的面积)存储在 area 变量中。 输出结果: console.log("圆的面积是: " + area + " 平方单位");:最后,打印出圆的面积计算结果。 在本例中,由于 circleRadius 为 7,输出将是 "圆的面积是: 153.93804002589985 平方单位"。

    练习五:随机消息生成器

     场景描述

    随机消息在增强应用和网站的用户体验中起着重要作用。 它们可以用于多种用途,从显示每日的励志名言到生成随机的用户提示,增加了惊喜和个性化的元素。 在JavaScript中实现一个随机消息生成器,可以提供动态内容,让用户体验保持新鲜和吸引人。

     练习代码

    function getRandomMessage() { const messages = [ "保持专注,永不放弃!", "相信你自己!", "每天都是一个新的开始。 ", "推动自己,因为没有人会替你努力。 ", "你可以做到的!" ]; // 选择一个随机消息 let randomIndex = Math.floor(Math.random() * messages.length); return messages[randomIndex]; } // 示例函数调用 let randomMessage = getRandomMessage(); // 输出结果 console.log("随机消息: " + randomMessage);

     详细说明

    getRandomMessage 函数不接受任何参数。 函数内部定义了一个包含各种励志名言或短语的数组 messages。 Math.random() * messages.length 生成一个 0 到 messages 数组长度之间的随机小数。 Math.floor 用于将这个小数向下取整,得到一个数组的有效索引。 函数返回在 messages 数组中随机索引位置的消息。 在示例中,我们调用了 getRandomMessage 函数,函数返回的随机消息存储在 randomMessage 变量中。 最后,我们使用 console.log 输出结果,展示随机消息。

     实际应用

    这个函数可以有效地应用于各种场景,例如: 用户互动:网站和应用可以使用此函数在每次用户访问或刷新页面时显示不同的励志名言或提示,增强用户互动。 游戏化:在游戏应用中,随机消息可以用于给玩家提供即兴挑战或奖励。 社交媒体平台:平台可以使用该函数向用户推荐随机帖子或话题,鼓励探索和互动。 这个简单而有效的 getRandomMessage 函数,是为提供动态内容的网页或移动应用程序的宝贵工具,旨在创造更具互动性和个性化的用户体验。

     代码分析

    function getRandomMessage() { const messages = [ "保持专注,永不放弃!", "相信你自己!", "每天都是一个新的开始。 ", "推动自己,因为没有人会替你努力。 ", "你可以做到的!" ]; let randomIndex = Math.floor(Math.random() * messages.length); return messages[randomIndex]; } 函数定义: function getRandomMessage:定义了一个名为 getRandomMessage 的新函数。 不接受任何参数。 消息数组: const messages = [...]:在函数内部定义了一个包含励志消息的数组 messages。 生成随机索引: Math.random() * messages.length:Math.random() 生成一个 0 到 1 之间的随机小数。 这个值乘以 messages 数组的长度,得到一个有效的数组索引范围。 Math.floor(...):将结果向下取整得到一个有效的数组索引。 选择并返回随机消息: return messages[randomIndex]:函数返回 messages 数组中 randomIndex 位置的消息。

     函数调用和结果

    let randomMessage = getRandomMessage(); console.log("随机消息: " + randomMessage); 函数调用和显示结果: let randomMessage = getRandomMessage();:调用 getRandomMessage 函数,返回值(随机选择的消息)存储在 randomMessage 变量中。 console.log("随机消息: " + randomMessage);:最后,打印出随机选择的消息。 在本例中,输出将是 messages 数组中的一条随机消息。

    prototype

    基础prototype

     全排列(力扣原题)

    要求以数组的形式返回字符串参数的所有排列组合。 注意: 字符串参数中的字符无重复且仅包含小写字母 返回的排列组合数组不区分顺序 const _permute = string => { const result = [] const map = new Map() const dfs = (path) => { if (path.length === string.length) { result.push(path) return } for (let i = 0; i < string.length; i++) { if (map.get(string[i])) continue map.set(string[i], true) path += string[i] dfs(path) path = path.substring(0, path.length - 1) map.set(string[i], false) } } dfs('') return result } console.log(_permute('abc')) // [ 'abc', 'acb', 'bac', 'bca', 'cab', 'cba' ]

     instanceof

    如果 target 为基本数据类型直接返回 false 判断 Fn.prototype 是否在 target 的隐式原型链上 const _instanceof = (target, Fn) => { if ((typeof target !== 'object' && typeof target !== 'function') || target === null) return false let proto = target.__proto__ while (true) { if (proto === null) return false if (proto === Fn.prototype) return true proto = proto.__proto__ } } function A() {} const a = new A() console.log(_instanceof(a, A)) // true console.log(_instanceof(1, A)) // false

     Array.prototype.map

    map 中的 exc 接受三个参数,分别是: 元素值、元素下标和原数组 map 返回的是一个新的数组,地址不一样 // 这里不能直接使用箭头函数,否则无法访问到 this Array.prototype._map = function(exc) { const result = [] this.forEach((item, index, arr) => { result[index] = exc(item, index, arr) }) return result } const a = new Array(2).fill(2) console.log(a.map((item, index, arr) => item * index + 1)) // [1,3] console.log(a._map((item, index, arr) => item * index + 1))// [1,3]

     Array.prototype.filter

    filter 中的 exc 接受三个参数,与map一致,主要实现的是数组的过滤功能,会根据 exc 函数的返回值来判断是否“留下”该值。 filter 返回的是一个新的数组,地址不一致。 Array.prototype._filter = function(exc) { const result = [] this.forEach((item, index, arr) => { if (exc(item, index, arr)) { result.push(item) } }) return result } const b = [1, 3, 4, 5, 6, 2, 5, 1, 8, 20] console.log(b._filter(item => item % 2 === 0)) // [ 4, 6, 2, 8, 20 ]

     Array.prototype.reduce

    reduce 接受两个参数,第一个为 exc 函数,第二个为初始值,如果不传默认为 0 reduce 最终会返回一个值,当然不一定是 Number 类型的,取决于你是怎么计算的,每次的计算结果都会作为下次 exc 中的第一个参数 Array.prototype._reduce = function(exc, initial = 0) { let result = initial this.forEach((item) => { result = exc(result, item) }) return result } console.log(b.reduce((pre, cur) => pre + cur, 0)) // 55 console.log(b._reduce((pre, cur) => pre + cur, 0)) // 55

     Object.create

    MDN[1] Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)。 Object.prototype._create = function(proto) { const Fn = function() { } Fn.prototype = proto return new Fn() } function A() { } const obj = Object.create(A) const obj2 = Object._create(A) console.log(obj.__proto__ === A) // true console.log(obj.__proto__ === A) // true

     Function.prototype.call

    call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。 Function.prototype._call = function(ctx, ...args) { // 如果不为空,则需要进行对象包装 const o = ctx == undefined ? window : Object(ctx) // 给 ctx 添加独一无二的属性 const key = Symbol() o[key] = this // 执行函数,得到返回结果 const result = o[key](...args) // 删除该属性 delete o[key] return result } const obj = { name: '11', fun() { console.log(this.name) } } const obj2 = { name: '22' } obj.fun() // 11 obj.fun.call(obj2) // 22 obj.fun._call(obj2) // 22

     Function.prototype.bind

    bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。 const obj = { name: '11', fun() { console.log(this.name) } } Function.prototype._bind = function(ctx, ...args) { // 获取函数体 const _self = this // 用一个新函数包裹,避免立即执行 const bindFn = (...reset) => { return _self.call(ctx, ...args, ...reset) } return bindFn } const obj2 = { name: '22' } obj.fun() // 11 const fn = obj.fun.bind(obj2) const fn2 = obj.fun._bind(obj2) fn() // 22 fn2() // 22

     New 关键字

    new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。 const _new = function(constructor) { // 创建一个空对象 const obj = {} // 原型链挂载 obj.__proto__ = constructor.prototype; // 将obj 复制给构造体中的 this,并且返回结果 const result = constructor.call(obj) // 如果返回对象不为一个对象则直接返回刚才创建的对象 return typeof result === 'object' && result !== null ? : result : obj }

     浅拷贝

    const _shallowClone = target => { // 基本数据类型直接返回 if (typeof target === 'object' && target !== null) { // 获取target 的构造体 const constructor = target.constructor // 如果构造体为以下几种类型直接返回 if (/^(Function|RegExp|Date|Map|Set)$/i.test(constructor.name)) return target // 判断是否是一个数组 const cloneTarget = Array.isArray(target) ? [] : {} for (prop in target) { // 只拷贝其自身的属性 if (target.hasOwnProperty(prop)) { cloneTarget[prop] = target[prop] } } return cloneTarget } else { return target } }

     深拷贝

    实现思路和浅拷贝一致,只不过需要注意几点 函数 正则 日期 ES6新对象 等不是直接返回其地址,而是重新创建 需要避免出现循环引用的情况 const _completeDeepClone = (target, map = new WeakMap()) => { // 基本数据类型,直接返回 if (typeof target !== 'object' || target === null) return target // 函数 正则 日期 ES6新对象,执行构造题,返回新的对象 const constructor = target.constructor if (/^(Function|RegExp|Date|Map|Set)$/i.test(constructor.name)) return new constructor(target) // map标记每一个出现过的属性,避免循环引用 if (map.get(target)) return map.get(target) map.set(target, true) const cloneTarget = Array.isArray(target) ? [] : {} for (prop in target) { if (target.hasOwnProperty(prop)) { cloneTarget[prop] = _completeDeepClone(target[prop], map) } } return cloneTarget }

    寄生组合式继承

    一图胜千言 function Parent(name) { this.name = name } Parent.prototype.getName = function() { return this.name } function Son(name, age) { // 这里其实就等于 this.name = name Parent.call(this, name) this.age = age } Son.prototype.getAge = function() { return this.age } Son.prototype.__proto__ = Object.create(Parent.prototype) const son1 = new Son('shao', 20) console.log(son1.getName()) // shao console.log(son1.getAge()) // 20

     发布订阅者模式

    class EventEmitter { constructor() { // key: 事件名 // value: callback [] 回调数组 this.events = {} } on(name, callback) { if (this.events[name]) { this.events[name].push(callback) } else { this.events[name] = [callback] } } off(name, callback) { if (!this.message[name]) return; if (!callback) { // 如果没有callback,就删掉整个事件 this.message[name] = undefined; } this.message[name] = this.message[name].filter((item) => item !== callback); } emit(name, ...args) { if (!this.events[name]) return this.events[name].forEach(cb => cb(...args)) } }

     观察者模式

    class Observerd { constructor() { // 我要看看到底有多少人在观察俺 this.observerList = [] } addObserver(observer) { // 添加一个观察俺的人 this.observerList.push(observer) } notify() { // 我要闹点动静,所有观察者都会知道这个信息,具体怎么做就是他们自己的事情了 this.observerList.forEach(observer => observer.update()) } } class Observer { constructor(doSome) { // 观察到小白鼠有动静之后,观察者做的事情 this.doSome = doSome } update() { console.log(this.doSome) } } const ob1 = new Observer('我是ob1,我观察到小白鼠有反应了,太饿了,我得去吃个饭了') const ob2 = new Observer('我是ob2,我观察到小白鼠有反应了,我要继续工作!') const xiaoBaiShu = new Observerd() xiaoBaiShu.addObserver(ob1) xiaoBaiShu.addObserver(ob2) xiaoBaiShu.notify() // .... .... 多说一句:怎么理解发布订阅者和观察者的区别呢 ? 其实发布订阅者模式只有一个中间者,好像啥事情都需要它亲自来做。 而且仔细观察的话,发布订阅者模式会存在一个事件名和事件的对应关系,今天可以发布天气预报,只有订阅了天气预报的才会被通知,订阅了 KFC疯狂星期四闹钟事件 的不会被提醒。 而观察者模式,等被观察者发出了一点动静(执行notify),所有观察者都会被通知。

     节流

    节流函数(throttle)就是让事件处理函数(handler)在大于等于执行周期时才能执行,周期之内不执行,即事件一直被触发,那么事件将会按每小段固定时间一次的频率执行。 function throttle(fn, delay = 300) { // 这里始终记得字节二面的时候,建议我不写 flag 好家伙 let isThrottling = false // 核心思路,函数多次执行只有当 isThrottling 为 false 时才会进入函数体 return function(...args) { if (!isThrottling) { isThrottling = true setTimeout(() => { isThrottling = false fn.apply(this, args) }, delay) } } }

     防抖

    事件响应函数在一段时间后才执行,如果这段时间内再次调用,则重新计算执行时间 function debounce(fn, delay = 300) { let timer = null return function(...args) { // 每次进来都会清空定时器,所以在 delay 事件中重复执行之后执行最后一次 clearInterval(timer) timer = setTimeout(() => { fn.apply(this, args) }, delay) } }

     once 函数

    函数返回结果会被缓存下来,只会计算一次。 const f = (x) => x; const onceF = once(f); //=> 3 onceF(3); //=> 3 onceF(4); const once = (fn) => { let res, isFirst = true return function(...args) { if (!isFirst) return res res = fn.call(this, ...args) isFirst = false return res } }

     累加函数应用

    实现一个累加函数,下面的几种情况都能正确的调用。 console.log(sum(1, 2)(3)()) // 6 console.log(sum(1)(2)(3)()) // 6 console.log(sum(1, 2, 4)(4)()) // 11 function sum(...args) { let params = args const _sum = (...newArgs) => { if (newArgs.length === 0) { return params.reduce((pre, cur) => pre + cur, 0) } else { params = [...params, ...newArgs] return _sum } } return _sum }

    进阶

     实现 repeat 方法

    function repeat(fn, times, delay) { return async function(...args) { for (let i = 0; i < times; i++) { await new Promise((resolve, reject) => { setTimeout(() => { fn.call(this, ...args) resolve() }, delay) }) } } } const repeatFn = repeat(console.log, 4, 1000) // 函数调用四次,每次间隔 1s 打印 hello repeatFn('hello')

     实现 Promise.all/race/allSettled/any

    Promise 身上的这些方法返回的都是一个 Promise Promise.resolve 接受一个 Promise,若非 promise 则将其变成功状态的 Promise // 有一个失败则返回失败的结果,全部成功返回全成功的数组 Promise.all = function(promiseList = []) { return new Promise((resolve, reject) => { const result = [] let count = 0 if (promiseList.length === 0) { resolve(result) return } for (let i = 0; i < promiseList.length; i++) { Promise.resolve(promiseList[i]).then(res => { result[i] = res count++ // 不能直接通过 result.length 进行比较,因为 会存在下标大的先赋值 // 例如 i = 3 第一个返回结果,此时数组变为[empty,empty,empty,res] if (count === promiseList.length) { resolve(result) } }).catch(e => { reject(e) }) } }) } // 返回第一个成功或失败的结果 Promise.race = function(promiseList = []) { return new Promise((resolve, reject) => { if (promiseList.length === 0) { return resolve([]) } for (let i = 0; i < promiseList.length; i++) { Promise.resolve(promiseList[i]).then(res => { resolve(res) }).catch(e => { reject(e) }) } }) } // 无论成功约否都返回,但是会添加一个 status 字段用于标记成功/失败 Promise.allSettled = function(promiseList = []) { return new Promise((resolve, reject) => { const result = [] let count = 0 const addRes = (i, data) => { result[i] = data count++ if (count === promiseList.length) { resolve(result) } } if (promiseList.length === 0) return resolve(result) for (let i = 0; i < promiseList.length; i++) { Promise.resolve(promiseList[i]).then(res => { addRes(i, { status: 'fulfilled', data: res }) }).catch(e => { addRes(i, { status: 'rejected', data: e }) }) } }) } // AggregateError,当多个错误需要包装在一个错误中时,该对象表示一个错误。 // 和 Promise.all 相反,全部失败返回失败的结果数组,有一个成功则返回成功结果 Promise.any = function(promiseList = []) { return new Promise((resolve, reject) => { if (promiseList.length === 0) return resolve([]) let count = 0 const result = [] for (let i = 0; i < promiseList.length; i++) { Promise.resolve(promiseList[i]).then(res => { resolve(res) }).catch(e => { count++ result[i] = e if (count === promiseList.length) { reject(new AggregateError(result)) } }) } }) }

     整数千分位加逗号

    1234567 -> 1,234,567 function toThousands(num) { num = num.toString() let result = '' while (num.length > 3) { result = ',' + num.substring(num.length - 3) + result num = num.substring(0, num.length - 3) } result = num + result return result } console.log(toThousands(1234567)) // 1,234,567 console.log(toThousands(123456)) // 123,456

     洗牌函数

    有几张牌张牌,用 js 来进行乱序排列,要保持公平性 const shuffle = (arr) => { // 不影响原来的数组 const result = [...arr] for (let i = result.length; i > 0; i--) { // 随机从 [0,i - 1] 产生一个 index, 将 i - 1 于 index 对应数组的值进行交换 const index = Math.floor(Math.random() * i); [result[index], result[i - 1]] = [result[i - 1], result[index]] } return result } const arr = [1, 2, 3, 4, 5] console.log(shuffle(arr)) // [ 3, 1, 2, 5, 4 ] console.log(shuffle(arr)) // [ 2, 3, 5, 1, 4 ] console.log(shuffle(arr)) // [ 4, 2, 3, 1, 5 ] console.log(shuffle(arr)) // [ 5, 4, 2, 3, 1 ]

     prototypeLRU

    LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法[2],选择最近最久未使用的页面予以淘汰。 该算法赋予每个页面[3]一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。 力扣地址[4] /** * @param {number} capacity */ var LRUCache = function(capacity) { this.map = new Map() this.capacity = capacity }; /** * @param {number} key * @return {number} */ LRUCache.prototype.get = function(key) { if(this.map.has(key)){ const value = this.map.get(key) // 更新存储位置 this.map.delete(key) this.map.set(key,value) return value } return - 1 }; /** * @param {number} key * @param {number} value * @return {void} */ LRUCache.prototype.put = function(key, value) { if(this.map.has(key)){ this.map.delete(key) } this.map.set(key,value) // 如果此时超过了最长可存储范围 if(this.map.size > this.capacity){ // 删除 map 中最久未使用的元素 this.map.delete(this.map.keys().next().value) } };

    更上一层楼

     Generator

    先看看下面输出的内容 async function getResult() { await new Promise((resolve, reject) => { setTimeout(() => { resolve(1); console.log(1); }, 1000); }) await new Promise((resolve, reject) => { setTimeout(() => { resolve(2); console.log(2); }, 500); }) await new Promise((resolve, reject) => { setTimeout(() => { resolve(3); console.log(3); }, 100); }) } getResult() // 1 2 3 那如何使用 Es6 中的 generator 实现类似的效果呢 ? function* getResult(params) { yield new Promise((resolve, reject) => { setTimeout(() => { resolve(1); console.log(1); }, 1000); }) yield new Promise((resolve, reject) => { setTimeout(() => { resolve(2); console.log(2); }, 500); }) yield new Promise((resolve, reject) => { setTimeout(() => { resolve(3); console.log(3); }, 100); }) } const gen = getResult() // gen.next().value 就是每一次 yield 之后返回的 Promise // gen.next() = {value: yeild 返回的数据,done: 迭代器是否走完} gen.next().value.then(() => { gen.next().value.then(() => { gen.next(); }); });// 依次打印 1 2 3 将 gen.next() 封装一层,让其自己能够实现递归调用 const gen = getResult() function co(g) { const nextObj = g.next(); // 递归停止条件:当迭代器迭代到最后一个 yeild if (nextObj.done) { return; } nextObj.value.then(()=>{ co(g) }) } co(gen)

     async-pool

    JS 控制并发请求, 参考文章 mp.weixin.qq.com/s/yWOPoef9i…[5] aysnc-pool 的基本使用 const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i)); await asyncPool(2, [1000, 5000, 3000, 2000], timeout); asyncPool 这个函数接受三个参数 poolLimit(数字类型):表示限制的并发数; array(数组类型):表示任务数组; iteratorFn(函数类型):表示迭代函数,用于实现对每个任务项进行处理,该函数会返回一个 Promise 对象或异步函数。 这里提醒一下,promise.then 中的函数执行是一异步的,而赋值是同步的 const a = Promise.resolve().then(()=>console.log(a)) // 等价于 此时 a 等于一个 pending 状态的 promise const a = Promise.resolve().then() a.then(()=>{ console.log(a) }) prototype实现,这部分可能会多花点时间。 可以拷贝代码多调试几次就知道了 async function asyncPool(poolLimit, array, iteratorFn) { const ret = []; // 存储所有的异步任务 const executing = []; // 存储正在执行的异步任务 for (const item of array) { // 调用iteratorFn函数创建异步任务 const p = Promise.resolve().then(() => iteratorFn(item, array)); ret.push(p); // 保存新的异步任务 // 当poolLimit值小于或等于总任务个数时,进行并发控制 if (poolLimit <= array.length) { // 当任务完成后,从正在执行的任务数组中移除已完成的任务 const e = p.then(() => executing.splice(executing.indexOf(e), 1)); executing.push(e); // 保存正在执行的异步任务 if (executing.length >= poolLimit) { await Promise.race(executing); // 等待较快的任务执行完成 } } } return Promise.all(ret); } const timeout = i => new Promise(resolve => setTimeout(() => { console.log(i); resolve(i) }, i)); // 当然,limit <= 0 的时候 我们可以理解为只允许一个请求存在 asyncPool(2, [1000, 5000, 3000, 2000], timeout).then(res => { console.log(res) }) 总共花费 6 s 时间,符合预期

    Change Themes

    换肤功能是一项普遍的需求,尤其是在夜晚,用户更倾向于使用暗黑模式。 过去主要使用 SCSS 变量,并利用其提供的函数,如 @each、map-get来实现换肤功能。 但因其使用成本高,只能适用于SCSS项目,于是改用 CSS 变量来实现换肤。 这样无论是基于 LESS 的 React 项目,还是基于 SCSS 的 Vue 项目,都能应用换肤功能。 并且使用时只需调用var函数,降低了使用成本。 Demo地址: https://github.com/cwjbjy/vite-vue-ts-seed/tree/feature/css

    1. 一键换肤

     1. 前置知识

    CSS变量:声明自定义CSS属性,它包含的值可以在整个文档中重复使用。 属性名需要以两个减号(--)开始,属性值则可以是任何有效的 CSS 值 --fontColor:'#fff' Var函数:用于使用CSS变量。 第一个参数为CSS变量名称,第二个可选参数作为默认值 color: var(--fontColor); CSS属性选择器:匹配具有特定属性或属性值的元素。 例如[data-theme='black'],将选择所有 data-theme 属性值为 'black' 的元素

     2. 定义主题色

      1. 新建src/assets/theme/theme-default.css

    这里定义字体颜色与布局的背景色,更多CSS变量可根据项目的需求来定义 [data-theme='default'] { /* 字体 */ --font-primary: #fff; --font-highlight: #434a50; /* 布局 */ --background-header: #2f3542; --background-aside: #545c64; --background-main: #0678be; }

      2. 新建src/assets/theme/theme-black.css

    再定义一套暗黑主题色 [data-theme='black'] { /* 字体 */ --font-primary: #fff; --font-highlight: #434a50; /* 布局 */ --background-header: #303030; --background-aside: #303030; --background-main: #393939; }

      3. 新建src/assets/theme/index.css

    在index.css文件中导出全部主题色 @import './theme-default.css'; @import './theme-black.css';

      4. 引入全局样式

    在入口文件引入样式,比如我这里是main.tsx import '@/assets/styles/theme/index.css';

     3. 在html标签上增加自定义属性

    修改index.html,在html标签上增加自定义属性data-theme <html lang="en" data-theme="default"></html> 这里使用data-theme是为了被CSS属性选择器[data-theme='default']选中,也可更换为其他自定义属性,只需与CSS属性选择器对应上即可。

     4. 修改CSS主题色

    关键点:监听change事件,使用document.documentElement.setAttribute动态修改data-theme属性,然后CSS属性选择器将自动选择对应的css变量 <template> <div> <select name="pets" @change="handleChange"> <option value="default">默认色</option> <option value="black">黑色</option> </select> <div>登录页面</div> </div> </template> <script setup lang="ts"> const handleChange = (e: Event) => { window.document.documentElement.setAttribute('data-theme', (e.target as HTMLSelectElement).value); }; </script> <style lang="scss"> body { color: var(--font-primary); background-color: var(--background-main); } </style> 效果图,默认色: 效果图,暗黑色:

     5. 修改JS主题色

    切换主题色,除了需要修改css样式,有时也需在js文件中修改样式,例如修改echarts的配置文件,来改变柱状图、饼图等的颜色。

      1. 新建src/config/theme.js

    定义图像的颜色,这里定义字体的颜色,默认情况下字体为黑色,暗黑模式下,字体为白色 const themeColor = { default: { font: '#333', }, black: { font: '#fff', }, }; export default themeColor;

      2. 修改vue文件

    关键点: 1. 定义主题色TS类型,规定默认和暗黑两种:type ThemeTypes = 'default' | 'black'; 2. 定义theme响应式变量,用来记录当前主题色:const theme = ref<ThemeTypes>('default'); 3. 监听change事件,将选中的值赋给theme:theme.value = selectTheme; 4. 使用watch进行监听,如果theme改变,则重新绘制echarts图形 完整的vue文件: <template> <div> <select name="pets" @change="handleChange"> <option value="default">默认色</option> <option value="black">黑色</option> </select> <div>登录页面</div> <div ref="echartRef" class="myChart"></div> </div> </template> <script setup lang="ts"> import { onMounted, ref, watch } from 'vue'; import themeColor from '@/config/theme'; import * as echarts from 'echarts'; type ThemeTypes = 'default' | 'black'; const echartRef = ref<HTMLDivElement | null>(null); const theme = ref<ThemeTypes>('default'); const handleChange = (e: Event) => { const selectTheme = (e.target as HTMLSelectElement).value as ThemeTypes; theme.value = selectTheme; window.document.documentElement.setAttribute('data-theme', selectTheme); }; const drawGraph = () => { let echartsInstance = echarts.getInstanceByDom(echartRef.value!); if (!echartsInstance) { echartsInstance = echarts.init(echartRef.value); } echartsInstance.clear(); var option = { color: ['#3398DB'], title: { text: '柱状图', left: 'center', textStyle: { color: themeColor[theme.value].font, }, }, xAxis: [ { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], axisLabel: { show: true, color: themeColor[theme.value].font, }, nameTextStyle: { color: themeColor[theme.value].font, }, }, ], yAxis: [ { type: 'value', axisLabel: { show: true, color: themeColor[theme.value].font, }, nameTextStyle: { color: themeColor[theme.value].font, }, }, ], series: [ { name: '直接访问', type: 'bar', barWidth: '60%', data: [10, 52, 200, 334, 390, 330, 220], }, ], }; echartsInstance.setOption(option); }; onMounted(() => { drawGraph(); }); watch(theme, () => { drawGraph(); }); </script> <style lang="scss"> body { color: var(--font-primary); background-color: var(--background-main); } .myChart { width: 300px; height: 300px; } </style>

    2. 一键变灰

    在特殊的日子里,网页有整体变灰色的需求。 可以使用filter 的 grayscale() 改变图像灰度,值在 0% 到 100% 之间,值为0%展示原图,值为100% 则完全转为灰度图像 body { filter: grayscale(1); //1相当于100% }

    communicate between two html pages

    WebRTC Real-time communication for the web Try using cookies. It's the simplest way I can think of. This website might seem helpful: https://www.w3schools.com/js/js_cookies.asp You can't do this with just JavaScript. The point is: JS is a client-side language which means that it is downloaded by a client (a browser) and is run by it (not by server). For the 2 pages to communicate, you have establish the communication somehow, via some medium. The medium can be: web itself. 2 clients can communicate directly, but only if they know each others' address. How would they get those? By the help of the server (which brings us to the second option below) or by manual configuration which is very impractical (some more details may be found in context of WebRTC) your server. Ok, that's the most common approach but that involves more than just JS: this requires a server-side language (PHP, Python, C++, Java, whatever) your browser. There's a special case where you can establish such a communication: if you open your second page in the same browser from your first page in a special way so that the second one is "under control" of the first one, you can "command" the second one to do some stuff from the first one So, if you're interested in the third option, you should read about window.open, window.opener, window.parent. var newWindow = window.open(url, name, params); will open a new window (say your second page) and bring you a variable newWindow which is a reference to the window object of the opened window. Try for instance newWindow.write("haha, I'm controlling this stuff!"); Likewise, in the second window you can use var oldWindow = window.opener; There's also a number of methods you can use (window``.close, .moveBy, .moveTo, .resizeBy, .resizeTo etc etc). Remember, however, that this interaction will be limited to your browser: if you change something as it is displayed in your browser (like add some text to a page) this won't affect the actual pages stored on your server because this requires your server do something via some server-side scripts. PS to advance this technique, you may want to read about window.postMessage but that's mostly designed for communication between pages that are cross-domain. PPS Actually, there's more! One thing to note is and have setItem method which generates 'storage' events on window (try localStorage.setItem('key', 'value'); and window.addEventListener('storage', event => console.log(event.key));). Another, like Anderson Green has noted, is Broadcast Channel API (try const channel = new BroadcastChannel('my_channel'), channel.postMessage('Hi there!') and channel.addEventListener('message', event => console.log(event))). There's also SharedWorkers and Service Workers. Finally, you can use some off-the-shelve solutions like . Those who speak Russian may also find more useful details in this article (wow!).

    web标签页相互通信

    内容

    了解css混合器(mixin); 了解动态自定义元素(标签)属性, el.setAttribute('data-activa', '');, setAttribute方法需要传递两个参数,第二个参数如果不传会报错; 可以传空字符串,此时标签只显示属性,等号和属性值不会显示, 标签结果 <span data-activa></span>; 传递的参数值都会转成字符串,比如null或undefined都会转成'null'或'undefined', 标签结果 <div data-activa="null"></div> <p data-activa="undefined"></p>; 了解自定义元素(标签)属性的选择器,.item[data-activa]|.item[data-activa='highlight ']; 了解window.open第二个参数的作用,以及固有值和自定义值对页面交互效果的区别; 了解标签页之间传参的区别; 了解storage监听中localStorage和sessionStorage的区别; 了解浏览器防多开功能的新思路或方法; 了解hover和active伪类; 最终效果类似网页版的酷狗,第一次播放打开新的标签页,之后的播放只发送音乐数据到播放页,此方法适用于防多开的功能。

    效果图

    公共代码和解析

     style-scss

    @mixin bsbb() { box-sizing: border-box; } html, body { margin: 0px; padding: 0px; @include bsbb(); } body { padding: 68px; @include bsbb(); } // 发送页 .box { >.item { cursor: pointer; list-style-type: none; padding: 8px 0px; @include bsbb(); text-align: center; font-size: 28px; font-weight: bold; background-color: #eeeeee; border-radius: 4px; } >.item:not(:first-child) { margin-top: 18px; } >.item:hover { background-color: #f0f8ff; } >.item:active { background-color: #00ffff; } >.item[data-activa] { color: #00ff00; background-color: #409eff; } } // 接收页 #idEl { height: calc(100vh - 136px); line-height: calc(100vh - 136px); margin: 0px; padding: 0px; text-align: center; font-size: 68px; font-weight: bold; } 使用Scss(一种CSS预处理器)编写一些样式和一个名为bsbb的mixin(混合器)。 1、@mixin bsbb()定义一个名为bsbb的mixin,它设置box-sizing属性为border-box。 box-sizing: border-box;确保元素的宽度和高度包括内容、内边距和边框,而不是仅仅包括内容。 2、html, body选择器设置html和body元素的margin和padding为0px,并调用bsbb混合器。 3、body选择器设置body元素的padding为68px,并再次调用bsbb混合器。 4、.box选择器定义.box类的样式,它包含一个.item类的子元素。 .box > .item选择器设置.item的样式,包括鼠标指针样式、无列表项标记、内边距、box-sizing、文本居中、字体大小、字体粗细、背景颜色和边框圆角。 5、.box > .item:not(:first-child)选择器设置除了第一个.item之外的所有.item的margin-top为18px。 6、.box > .item:hover选择器定义鼠标悬停在.item上时的背景颜色。 7、.box > .item:active选择器定义当.item被激活(例如点击)时的背景颜色。 8、.box > .item[data-activa]选择器定义当.item元素具有data-activa属性时的文本颜色和背景颜色。 9、#idEl选择器定义具有id为idEl的元素样式,它设置高度和行高为视口高度减去136px,margin和padding为0px,文本居中,字体大小为68px,字体粗细为粗体。 .box类定义一个包含多个.item的容器,每个.item可以有不同的交互状态和样式。 #idEl定义一个特定的元素,其样式可能用于页面的特定部分,如发送页和接收页。 在实际使用中,这段代码需要被编译成普通的css文件,以便在网页中使用。 Scss编译器会处理这些mixin和选择器,生成相应的CSS规则。

     style-css

    html, body { margin: 0px; padding: 0px; box-sizing: border-box; } body { padding: 68px; box-sizing: border-box; } .box>.item { cursor: pointer; list-style-type: none; padding: 8px 0px; box-sizing: border-box; text-align: center; font-size: 28px; font-weight: bold; background-color: #eeeeee; border-radius: 4px; } .box>.item:not(:first-child) { margin-top: 18px; } .box>.item:hover { background-color: #f0f8ff; } .box>.item:active { background-color: #00ffff; } .box>.item[data-activa] { color: #00ff00; background-color: #409eff; } #idEl { height: calc(100vh - 136px); line-height: calc(100vh - 136px); margin: 0px; padding: 0px; text-align: center; font-size: 68px; font-weight: bold; }

     html

    发送页(send) <ul class="box"> <li class="item" onclick="handle(1)">1</li> <li class="item" onclick="handle(2)">2</li> <li class="item" onclick="handle(3)">3</li> <li class="item" onclick="handle(4)">4</li> <li class="item" onclick="handle(5)">5</li> </ul> 接收页(receive) <div id="idEl"></div>

     window.open的解析

    window.open方法的第二个参数用于指定新窗口的名称,名称可以用来引用新窗口,例如在后续的代码中使用window.open或window.close方法来操作这个窗口。 第二个参数如果是_blank,则表示新窗口或标签页将在浏览器中打开,但不会与任何已存在的窗口或标签页关联。 这通常用于打开一个全新的、独立的窗口或标签页。 第二个参数如果是_self,则表示新页面将在当前窗口或标签页中加载,这将替换当前页面的内容。 第二个参数如果是_parent,则表示新页面将在当前窗口或标签页的父窗口或标签页中加载。 如果当前窗口或标签页没有父窗口或标签页(即它不是嵌套的),则效果与_self相同。 第二个参数如果是_top,则表示新页面将在最顶层的窗口中加载,这将替换所有嵌套的窗口或标签页。 第二个参数如果是自定义(keyOnly),且不是一个标准的窗口名称,它不会影响新窗口的行为。 如果自定义(keyOnly)不是已存在的窗口名称,那么window.open会创建一个新窗口,并将其命名为keyOnly。 如果keyOnly已经是一个打开的窗口的名称,那么window.open将不会创建新窗口,而是返回对已存在的窗口的引用。 在实际应用中,使用非标准的窗口名称(如keyOnly)可能不会达到预期的效果,因为浏览器可能不会识别这样的名称。 通常建议使用_blank、_self、_parent或_top作为第二个参数,以确保与浏览器的兼容性。

     localStorage和sessionStorage的监听区别和注意事项(坑)

    localStorage和sessionStorage的区别 localStorage和sessionStorage都是Web Storage API提供的两种存储机制,用于在客户端存储数据。 它们在存储方式、生命周期、作用域等方面有所不同。 1、生命周期 localStorage,数据没有过期时间,除非被显式删除,否则数据会一直保存在浏览器中,即使关闭浏览器或重启计算机。 sessionStorage,数据仅在当前浏览器会话中有效,一旦会话结束(例如,关闭浏览器标签页或窗口),数据就会被清除。 2、作用域 localStorage和sessionStorage都基于源(origin),这意味着它们只能访问相同协议、域名和端口的数据。 不同源之间的数据存在隔离(跨域)。 localStorage的数据在所有同源的窗口和标签页中共享,而sessionStorage的数据仅限于创建它的窗口或标签页。 3、存储大小 localStorage和sessionStorage的存储大小限制因浏览器而异,但通常localStorage的存储空间比sessionStorage大。 在大多数现代浏览器中,localStorage的大小限制大约为5MB到10MB。 4、API接口 两者都提供了相同的API方法,包括setItem(key, value)、getItem(key)、removeItem(key)、clear()和key(index)。 5、使用场景 localStorage适合存储长期数据,如用户偏好设置、登录状态等。 sessionStorage适合存储临时数据,如表单输入、购物车内容等,这些数据仅在当前会话中需要。 6、数据持久性 localStorage提供持久化存储,即使关闭浏览器或重启计算机,数据仍然存在。 sessionStorage提供临时存储,数据仅在当前会话期间有效。 7、事件监听 两者都支持storage事件,当数据发生变化时,所有同源的窗口都会接收到这个事件。 但sessionStorage事件只在当前会话的窗口中触发。 在使用时,根据具体需求选择合适的存储机制。 如果需要存储用户登录状态,localStorage是一个很好的选择,因为它可以跨会话持久化数据。 如果需要存储用户在单个页面会话中的临时数据,sessionStorage可能更适合,因为它不会在会话结束后保留数据。 解决storage监听不被触发的问题 如果在两个页面中,只有使用localStorage时storage事件才会被触发,而使用sessionStorage时不会,这可能是因为storage事件的触发机制和sessionStorage的特性导致。 storage事件被触发的条件1、当localStorage或sessionStorage中的任何数据被修改时(例如,通过setItem、removeItem或clear方法)。 2、事件会在所有同源的页面中触发,无论这些页面是打开在同一个标签页还是不同的标签页。 sessionStorage的特性1、sessionStorage与特定的浏览器标签页或窗口关联。 这意味着,如果在标签页A中修改sessionStorage,只有标签页A会接收到storage事件。 其他标签页(即使它们是同一个源)不会接收到这个事件,因为它们的sessionStorage独立。 2、当标签页关闭时,与该标签页关联的sessionStorage会被清除。 据上,如果在两个不同的标签页中分别修改sessionStorage,每个标签页只会接收到自己修改的事件,而不会接收到另一个标签页的事件。 这就是为什么在两个页面中,只有使用localStorage时storage事件才会被触发的原因。 如果希望在两个标签页中都能监听到sessionStorage的变化,需要确保两个标签页都注册storage事件监听器,并且它们都属于同一个源。 这样,无论哪个标签页修改sessionStorage,另一个标签页都能接收到storage事件。 sessionStorage的事件监听只在修改它的标签页中触发,而localStorage的事件监听则在所有同源的标签页中触发。 如果需要跨标签页监听sessionStorage的变化,需要确保所有相关标签页都注册storage事件监听器,并且它们都属于同一个源。

    openKeyOnly方式(壹)

    发送页(send) function handle(val) { window.open(`./receive.html?val=${val}&type=keyOnly`, 'keyOnly'); } 接收页(receive) const search = window.location.search; const searchParams = new URLSearchParams(search); const iterator = searchParams.keys(); const obj = {}; for (let item of iterator) obj[item] = searchParams.get(item); idEl.textContent = obj.val; 解析 代码用于处理一个网页的URL查询参数,并将特定的参数值显示在页面上。 1、function handle(val)定义一个名为handle的函数,它接受一个参数val。 2、window.open('./receive.html?val=${val}&type=keyOnly', 'keyOnly');调用window.open方法打开一个新的浏览器窗口或标签页。 它将打开./receive.html页面,并通过URL查询字符串传递两个参数val和type。 val参数的值通过函数参数val赋值,type参数的值被硬编码为keyOnly。 'keyOnly’是新窗口的名称。 3、const search = window.location.search;获取当前页面URL查询字符串部分,并将其赋值给变量search。 如果当前URL是http://example.com/page.html?param1=value1&param2=value2,那么search的值将是?param1=value1&param2=value2。 4、const searchParams = new URLSearchParams(search);使用URLSearchParams构造函数创建一个新的URLSearchParams对象,该对象封装search字符串中的查询参数。 URLSearchParams对象提供一种方便的方式来处理URL的查询字符串。 5、const iterator = searchParams.keys();调用searchParams对象的keys()方法,该方法返回一个迭代器,它包含查询字符串中的所有键(参数名)。 6、const obj = {};创建一个空对象obj,用于存储查询参数的键值对。 7、for (let item of iterator) obj[item] = searchParams.get(item);使用for...of循环来遍历iterator中的每个键(参数名)。 对于每个键,它使用searchParams.get(item)方法获取对应的值,并将这个键值对存储在obj对象中。 8、idEl.textContent = obj.val;将obj对象中val键对应的值赋给idEl元素的textContent属性。 idEl是一个页面上的DOM元素,其ID为idEl。 假设val参数存在于URL查询字符串中,并且idEl元素存在。 总结来说,以上代码的目的是从当前页面的URL查询字符串中提取val参数的值,并将其显示在页面上。 如果val参数不存在,idEl.textContent将不会被设置。 此外,这段代码还定义一个handle函数,用于打开一个新页面并传递参数。

    BroadcastChannel方式(贰)

    叙言 以下代码展示两个页面之间的通信机制,一个发送消息页面,一个接收消息页面。 使用BroadcastChannelAPI来实现跨页面通信,以及localStorage来存储和传递消息计数。 发送页(send) const channel = new BroadcastChannel('keyOnly'); function handle(val) { const n = +localStorage.getItem('keyOnly'); if (!isNaN(n) && n > 0) { channel.postMessage({ val, type: 'keyOnly' }); } else { window.open(`./receive.html?val=${val}&type=keyOnly`, '_blank'); } }1、const channel = new BroadcastChannel('keyOnly');创建一个新的BroadcastChannel对象,用于在同源的不同页面之间发送和接收消息。 频道名称为keyOnly。 2、function handle(val) { ... }定义一个handle函数,它接收一个参数val,这个参数是需要发送的消息内容。 3、const n = +localStorage.getItem('keyOnly');从localStorage中获取名为keyOnly的项,并尝试将其转换为数字。 +操作符用于尝试将字符串转换为数字。 4、if (!isNaN(n) && n > 0) { ... } else { ... }如果localStorage中的值存在,且为正数,则执行channel.postMessage发送消息;否则,打开一个新的浏览器窗口或标签页,并加载./receive.html页面。 5、channel.postMessage({ val, type: 'keyOnly' });如果条件满足,使用BroadcastChannel发送一个包含val和type属性的对象。 接收页(receive) const search = window.location.search; const searchParams = new URLSearchParams(search); const iterator = searchParams.keys(); const obj = {}; for (let item of iterator) obj[item] = searchParams.get(item); idEl.textContent = obj.val; let n = +localStorage.getItem('keyOnly'); const channel = new BroadcastChannel('keyOnly'); if (isNaN(n)) n = 0; n += 1; localStorage.setItem('keyOnly', n); window.addEventListener('unload', () => { let n = +localStorage.getItem('keyOnly'); if (isNaN(n)) n = 1; n -= 1; localStorage.setItem('keyOnly', n); }); channel.addEventListener('message', ({ data: { val } }) => { idEl.textContent = val; });1、const search = window.location.search;获取当前页面的查询字符串部分。 2、const searchParams = new URLSearchParams(search);使用URLSearchParams解析查询字符串。 3、const iterator = searchParams.keys();获取查询参数的键的迭代器。 4、const obj = {};创建一个空对象obj用于存储查询参数。 5、for (let item of iterator) obj[item] = searchParams.get(item);遍历查询参数的键,并将它们及其对应的值存储在obj对象中。 6、idEl.textContent = obj.val;将obj对象中val键对应的值设置为idEl元素的文本内容。 7、let n = +localStorage.getItem('keyOnly');从localStorage中获取名为keyOnly的项,并尝试将其转换为数字。 8、const channel = new BroadcastChannel('keyOnly');创建一个新的BroadcastChannel对象,用于接收消息。 9、if (isNaN(n)) n = 0; n += 1; localStorage.setItem('keyOnly', n);如果localStorage中的值不存在或不是数字,则将其设置为1,并增加计数,用于计算当前打开的页面数。 10、window.addEventListener('unload', () => { ... });添加一个事件监听器,当页面卸载时(例如,用户关闭标签页或导航到另一个页面),减少计数并更新localStorage。 11、channel.addEventListener('message', ({ data: { val } }) => { ... });添加一个事件监听器,当通过BroadcastChannel接收到消息时,将消息内容设置为idEl元素的文本内容。 总结 发送页面通过BroadcastChannel发送消息,接收页面通过BroadcastChannel接收消息。 发送页面在发送消息前会检查localStorage中的计数,如果计数为0,则通过打开新窗口的方式发送消息;否则,通过BroadcastChannel发送消息。 接收页面在接收到消息后,会更新页面上的idEl元素的文本内容。 此外,还跟踪接收页面打开的次数,当页面卸载时减少计数,并在每次打开新的接收页面时增加计数。 这样可以确保发送页面在发送消息时,可以根据计数决定使用BroadcastChannel发送还是打开新窗口发送。

    localStorage方式(叁)

    叙言 以下代码展示两个页面之间的通信机制,一个页面发送消息,另一个页面接收消息。 发送页面使用localStorage和window.open来发送消息,接收页面使用localStorage和window.addEventListener来接收消息。 发送页(send) const liEl = document.querySelectorAll('.item'); const val = JSON.parse(localStorage.getItem('pageItem'))?.val || 1; handle(val); function handle(val) { const n = +localStorage.getItem('keyOnly'); const pageItem = { val, type: 'keyOnly' }; const setItem = (data) => localStorage.setItem('pageItem', JSON.stringify(data)); if (!isNaN(n) && n > 0) { setItem(pageItem); } else { setItem(pageItem); window.open('./receive.html', '_blank'); } liEl.forEach(item => { if (item.textContent == val) { item.setAttribute('data-activa', ''); } else { item.removeAttribute('data-activa'); } }); } window.addEventListener('storage', ({ key, storageArea, newValue }) => { if (storageArea && key === 'keyOnly') { if (newValue == 0) { liEl.forEach(item => { item.removeAttribute('data-activa'); }); localStorage.removeItem('pageItem'); localStorage.removeItem('keyOnly'); } } });1、const liEl = document.querySelectorAll('.item');选择页面上所有类名为item的元素。 2、const val = JSON.parse(localStorage.getItem('pageItem'))?.val || 1;从localStorage中获取名为pageItem的项,并尝试将其解析为JSON对象。 如果解析失败或不存在,则val默认为1。 3、handle(val);调用handle函数并传入val作为参数。 4、function handle(val) { ... }定义handle函数,用于处理发送消息的逻辑。 5、const n = +localStorage.getItem('keyOnly');从localStorage中获取名为keyOnly的项,并尝试将其转换为数字。 6、const pageItem = { val, type: 'keyOnly' };创建一个对象pageItem,包含val和type属性。 7、const setItem = (data) => localStorage.setItem('pageItem', JSON.stringify(data));定义一个函数setItem,用于将对象转换为JSON字符串并存储到localStorage中。 8、if (!isNaN(n) && n > 0) { ... } else { ... }如果localStorage中的keyOnly项存在且为正数,则调用setItem函数存储pageItem对象;否则,打开./receive.html页面。 9、liEl.forEach(item => { ... });遍历所有item元素,如果元素的文本内容与val相等,则设置data-activa属性;否则,移除该属性。 10、window.addEventListener('storage', ({ key, storageArea, newValue }) => { ... });添加一个事件监听器,当localStorage发生变化时触发。 如果变化的键是keyOnly且新值为0,则移除所有item元素的data-activa属性,并清除pageItem和keyOnly的存储。 接收页(receive) let pageItem = localStorage.getItem('pageItem'); let n = +localStorage.getItem('keyOnly'); let setEl = (info) => { info = JSON.parse(info); idEl.textContent = info.val; }; setEl(pageItem); window.addEventListener('storage', ({ key, storageArea, newValue }) => { if (storageArea && key === 'pageItem') setEl(newValue); }); if (isNaN(n)) n = 0; n += 1; localStorage.setItem('keyOnly', n); window.addEventListener('unload', () => { let n = +localStorage.getItem('keyOnly'); if (isNaN(n)) n = 1; n -= 1; localStorage.setItem('keyOnly', n); });1、let pageItem = localStorage.getItem('pageItem');从localStorage中获取名为pageItem的项。 2、let n = +localStorage.getItem('keyOnly');从localStorage中获取名为keyOnly的项,并尝试将其转换为数字。 3、let setEl = (info) => { ... };定义一个函数setEl,用于将传入的JSON字符串解析并更新页面上的idEl元素的文本内容。 4、setEl(pageItem);调用setEl函数,传入pageItem,更新页面。 5、window.addEventListener('storage', ({ key, storageArea, newValue }) => { ... });添加一个事件监听器,当localStorage发生变化时触发。 如果变化的键是pageItem,则调用setEl函数更新页面。 6、if (isNaN(n)) n = 0; n += 1; localStorage.setItem('keyOnly', n);如果localStorage中的keyOnly项不存在或不是数字,则将其设置为0,并增加计数。 7、window.addEventListener('unload', () => { ... });添加一个事件监听器,当页面卸载时触发。 如果localStorage中的keyOnly项存在且为数字,则将其减1。 总结 发送页面通过localStorage和window.open发送消息,接收页面通过localStorage和window.addEventListener接收消息。 发送页面在发送消息前会检查localStorage中的计数,如果计数为0,则通过打开新窗口的方式发送消息;否则,通过localStorage发送消息。 接收页面在接收到消息后,会更新页面上的idEl元素的文本内容。 此外,接收页面还跟踪发送页面发送消息的次数,当页面卸载时减少计数,并在每次发送消息时增加计数。 这样可以确保发送页面在发送消息时能够根据计数决定是通过localStorage发送还是通过打开新窗口发送。

    三种方式的区别

    1、方式壹和方式贰的区别 1.1、方式壹通过自定义窗口(页面)名称来打开新窗口,并通过自定义名称检测是否已有相同名称的窗口(页面)存在;没有则打开新窗口(页面),有则刷整个窗口(页面)。 1.2、方式贰通过本地存储的keyOnly判断是否第一次打开新窗口(页面),如果是就直接使用window.open打开页面,否则通过BroadcastChannel传参给接收页面,不用再次打开新窗口(页面)。 1.3、两种方式的传参区别,方式壹通过URL传参,并且自定义窗口(页面)名称,使其永远只打开一个相同名称的窗口(页面),但用户体验不是很好,因为每次打开都刷新整个页面(窗口);方式贰首次打开通过URL传参,第二次传参则通过BroadcastChannel实现,此操作对接收页面的代码编写不友好,接收页面需要编写两套代码来实现数据接收的工作,第一套是通过RUL接收参数;第二套是通过BroadcastChannel接收参数。 2、方式贰和方式叁的区别 2.1、方式贰的实现本质已在第一大点中叙述,此处不在赘叙。 2.2、方式叁通过本地缓存的方式实现参数的传递;第一次打开新窗口之前先把参数缓存在本地,接收页加载的时候直接从缓存中获取即可;再次传参也是本地缓存,但接收页面则通过监听缓存变化来获取参数。 3、三种方式各自的优缺点 优点 方式壹,较好的解决窗口多开的问题; 方式贰,解决页面整体刷新的问题; 方式叁,解决接收页面写两套接收代码的问题。 缺点 方式壹,每次传参都会整体刷新页面,用户体验感不好; 方式贰,传参的方式复杂,接收参数也麻烦,首次打开时通过URL传参,二次传参则通过BroadcastChannelAPI;此方式增加接收页的代码量和代码逻辑复杂度。 并且不能像方式壹一样很好的解决窗口多开问题; 方式叁,不能像方式壹一样很好的解决窗口多开问题,有时候会发生多开的情况。 4、总结 如果侧重防多开功能,建议使用第一种方式; 如果侧重传参和用户体验,建议使用第三种方式; 第三种方式存有可优化空间(待优化…),视情况选择合适自己的方式。

    浏览器跨标签页通信


    一、概说

    为了提高稳定性,每个标签页都是一个独立的浏览器上下文,它们之间是相互隔离的,一个标签页崩溃不会影响到其他标签页,无法直接访问对方的数据或进行通信。 浏览器跨标签页通信是指在同一浏览器的不同Tab标签页或窗口之间进行数据交互,通过跨标签页通信,可以实现数据的共享、状态的同步、消息的传递等功能。 简单说就是,所有的浏览器都支持多标签页的,我们可以在一个浏览器中打开多个标签页,每个标签页访问不同的网站内容,一个标签页能够发送信息给另一个标签页。 已下图为例,当a.html标签页发送一个消息时,b.html和c.html可以接收到来自a.html的消息,这就是跨标签页通信。 在日常项目开发中,虽然不经常用到,但还是很有价值的,遇到一些应用场景时可以信手拈来。 常见场景如下: 登录或登出:当用户打开多个标签页时,在某个标签页登录或登出需要通知其它所有标签页更新状态。 消息同步:当用户在一个标签页收到新的消息或通知时,需要将这一状态或消息内容传递给所有打开的页面,以实现实时提醒功能。 共享资源:在某些场景下,可能需要在多个标签页之间共享某些资源,如网络连接、音频/视频播放器等。

    实现浏览器跨标签页通信方式

    二、localStorage和sessionStorage事件

    当一个页面修改了localStorage或sessionStorage,其它页面会收到一个事件提示,修改了localStorage或sessionStorage的页面不会收到这个事件。 // a.html <button type="button">点击</button> <script type="text/javascript"> const btn = document.getElementById('btn'); btn.addEventListener('click', () => { localStorage.setItem('sendKey', "a向b发送了消息:吃饭了吗? ") console.log("a向b发送了消息:吃饭了吗? ") }) </script> // b.html window.addEventListener('storage', function(event) { console.log(event) if(event.key === 'sendKey') { const newValue = event.newValue; console.log(newValue) localStorage.setItem('sendKey', newValue) } }) 当 localStorage 或 sessionStorage 被修改时,将触发 storage 事件,判断对应 key 值是否发生变化。 当 localStorage 或 sessionStorage 不变时,不会触发 storage 事件。 此方法的操作简单,代码简单,不需要一些复杂的状态同步逻辑。 缺点如下: 如果用户禁用了浏览的LocalStorage该方案就无效了。 当前页的 setItem 不会触发当前页的 storage 事件,只会触发其它窗口的。 要通信的标签页必须是同域的。

    三、BroadcastChannel

    Broadcast Channel,即广播频道接口,客户端通过创建 BroadcastChannel 对象加入广播频道。 其构造函数只接受一个参数:频道的名称。 如果它是第一个连接到该广播频道名称的客户端,则会创建底层频道。 const bc = new BroadcastChannel("test_channel");

    发送消息:

    在创建的 BroadcastChannel 对象上调用 postMessage() 方法就足够了,该方法接受任何对象作为参数。 bc.postMessage("你吃饭了吗?");

    接收消息:

    发布消息时,会向连接到此频道的每个 BroadcastChannel 对象发送一个 message 事件。 可以使用 onmessage 事件处理器。 bc.onmessage = (event) => { console.log(event); };

    断开频道:

    要离开频道,请调用对象上的 close() 方法。 这会断开对象与底层频道的连接,从而允许垃圾回收。 bc.close(); BroadcastChannel构造函数可以创建一个新的频道,然后各个标签页通过监听和发布消息进行通信。 每个标签页都可以创建一个与之前频道同名的BroadcastChannel对象,然后就可以通过postMessage方法来进行发送消息,再通过onmessage事件来接受消息。 // a.html <button id="btn" type="button" id="btn">点击</button> <script type="text/javascript"> const btn = document.getElementById('btn'); // 创建 BroadcastChannel 实例 const bs = new BroadcastChannel('pay'); // 点击事件 btn.addEventListener('click', () => { // 发送消息 bs.postMessage({ message: '支持成功,刷新状态' }); // 关闭频道 bs.close(); }) </script>// b.html // 创建 BroadcastChannel 实例 const bs = new BroadcastChannel('pay'); // 监听频道的消息 bs.onmessage = (event) => { console.log(event) } 适用于在同一域下的多个窗口、标签页或 iframe 之间进行实时消息广播。

    四、SharedWorker

    SharedWorker 接口代表一种特定类型的 worker,可以从几个浏览上下文中访问,例如几个窗口、iframe 或其他 worker。 它们实现一个不同于普通 worker 的接口,具有不同的全局作用域。 如果要使 SharedWorker 连接到多个不同的页面,这些页面必须是同源的(相同的协议、host 以及端口)。 创建一个执行指定 url 脚本的共享 web worker。 const myWorker = new SharedWorker("./worker.js");如果已经用 addEventListener 监听了 onmessage 事件,则可以使用 start() 方法手动启动端口。 myWorker.port.start(); // a.html <button type="button" id="btn">点击</button> <script type="text/javascript"> const btn = document.getElementById('btn'); // 创建一个 SharedWorker const worker = new SharedWorker('./worker.js'); btn.addEventListener('click', function(e) { // port.postMessage发送消息 worker.port.postMessage({ status: 'SUCCESS', message: '支付成功' }); }) </script> 创建worker.js const ports = []; onconnect = function(e) { const port = e.ports[0]; ports.push(port); port.onmessage = function(e) { console.log("worker接收到的消息:", e.data); ports.forEach((p) => { p.postMessage(e.data); }); }; }; b.html // b.html const worker = new SharedWorker('./worker.js'); const port = worker.port; // onmessage接收消息 port.onmessage = function(event) { console.log('接收:', event.data); };

    SharedWorker的特点:

    SharedWorker多页面共享线程只限于同一浏览器,而不能跨浏览器。 共享实例,多个上下文共享一个worker实例,节省资源。 同源策略,SharedWorker 连接到多个不同的页面必须是同源的。 双向通信,可以在当前页面通过portMessage发送消息,也可以在当前页面通过onmessage接收消息。

    五、Cookie

    Cookies 是存储在用户计算机上的小文件,它们通常用于存储用户的偏好设置、跟踪用户会话等。 同一个域名下的不同标签页可以共享 Cookies 数据,从而实现跨标签页的通信。 在一个标签页中设置 Cookie,然后在其他标签页中读取该 Cookie,并根据其值执行相应的操作。 设置Cookie: function setCookie(key, value, d) { const date = new Date(); date.setTime(date.getDate() + d*24*60*60*1000); const expires = date.toUTCString(); document.cookie = `${key}=${value};expires=${expires};path=/;domain=${window.location.host}`; } setCookie('message', 'SUCCESS', 7) 获取cookie: function getCookie(cname) { const name = cname + "="; const cookieValue = document.cookie.split(';'); for(let i = 0; i < cookieValue.length; i++) { const str = cookieValue[i].trim(); if (str.indexOf(name) == 0) { return str.substring(name.length,str.length); } } return ""; }getCookie('message'); //SUCCESS 由于我们不能实时监听到Cookie的变化,因此在接收消息的标签页中,我们可以创建一个setInterval定时器,每隔一段时间轮询 Cookie 中的数据。 通过解析和处理 Cookie,我们可以获取到存储的消息,并进行相应的处理。 由于 Cookie 的大小有限制,通常为几 KB。 如果需要发送的消息较大,可能需要拆分成多个 Cookie 进行存储。 Cookie 默认只能在同一域名下共享。 如果需要在不同域名下进行跨标签页通信,需要设置合理的域名domain和路径path。 下面就重点介绍一下domain和path的作用。

    Cookie的domain属性:

    表示cookie所在的域,默认为请求的地址,如网址为a.test.com/public/a.html,那么domain默认为a.test.com。 如域A为a.test.com,域B为b.test.com,那么在域A生产一个令域A和域B都能访问的cookie就要将该cookie的domain设置为.test.com; 如果要在域A生产一个令域A不能访问而域B能访问的cookie就要将该cookie的domain设置为b.test.com。

    Cookie的path属性:

    表示cookie所在的目录,默认为 /,就是根目录。 如在同一个服务器上有目录 /public/,/public/dir1/,/public/dir2/,现设一个cookie A的path为 /public/,cookie B 的path为 /public/dir1/,那么public下的所有页面都可以访问到 cookie A,而 /public/ 和 /public/dir2/ 的子页面不能访问 cookie B。 这是因为 cookie 能让其path路径下的页面访问。 默认情况下,cookie对创建它的页面和域与创建它的页面在同一目录的其它页面以及创建它的页面所在目录的子目录的其它页面可见,例如,www.test.com/public/a.html 创建的cookie对www.test.com/public/b.html 和 www.test.com/public/views/c.html 都是可见的,但对www.test.com/d.html不可见。 可以设置cookie的path属性,只要以path指定的路径前缀开始的同一服务器的页面均可见cookie,例如,设置path=/public,则www.test.com/public/views/c.html 创建的 cookie 对www.test.com/public/b.html也是可见的; 设置path=/,则cookie对www.test.com这台服务器上的页面均可见。 一级域名相同,只是二级域名不同的情况下,浏览器允许通过设置document.domain共享Cookie。 也就是说,Cookie只能跨二级域名来访问,不能跨一级域名来访问。 a.test.com要读取b.test.com设置的cookie值,可以将path设置为/,domain设置为test.com,则a.test.com设置的cookie对b.test.com以及其它所有.test.com的域都是可见的。

    六、WebSocket

    可以利用服务端做为中介进行跨标签页通信。 WebSocket 最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。 WebSocket 使用一个长连接,在客户端和服务器之间保持持久的连接,从而可以实时地发送和接收数据。

    onopen:

    客户端和服务器建立连接后触发,被称为客户端和服务器之间的初始握手。 如果接收到open, 说明已经连接成功,可以进行通信了。

    onmessage:

    接收到消息时触发。 服务器发送给客户端的消息可包括纯文本消息,二进制数据(Blob消息或者ArrayBuffer消息)。

    onerror:

    响应意外故障时触发,在错误之后总是会终止连接。

    onclose:

    连接关闭时触发。 一旦连接关闭后,客户端和服务端将不会再进行消息的收发。 也可主动调用close()方法关闭连接。 // 创建WebSocket对象,并指定服务器的地址 const socket = new WebSocket("ws://your-websocket-server.com"); // 与服务器建立连接:发送消息到服务器 socket.onopen = () => { console.log("connect: "); }; // 收到服务器发送的消息:event处理服务器返回的数据 socket.onmessage = (event) => { console.log("receive: ", event.data); }; // 连接或通信过程中发生错误 socket.onerror = (event) => { console.log("errror: ", event.error); }; // 与服务器断开连接 socket.onclose = (event) => { console.log("close: ", event.code); };

    WebSocket的应用场景:

    WebSocket主要应用于需要实时、双向通信的web应用中,如: 即时聊天:构建实时聊天应用,用户可以实时发送和接收消息,实现低延迟、高效的在线交流。 金融市场:股票、外汇、期货等金融市场的实时报价、交易提醒。 新闻与社交媒体:实时推送通知。 物联网(IoT):设备的状态监控与远程控制,如智能家居、工业自动化等。 协作工具:在线文档编辑、白板绘图、代码协作等需要多方实时同步内容的应用。 游戏:多人在线游戏中的实时状态同步、玩家交互。 地理位置服务:实时位置追踪、导航应用中的动态路线更新。 直播互动:直播平台的实时评论、弹幕、礼物赠送等互动功能。 数据分析与监控:实时仪表盘、日志流处理、性能监控系统的实时数据展示与报警。

    总结

    选择通信方式:根据具体需求(如是否需要跨域、是否需要实时通信、通信数据的复杂程度等)选择合适的通信方式。 安全性:无论采用哪种方式,都需要注意数据的安全性,特别是当涉及到跨域通信时。 兼容性:考虑到不同浏览器的兼容性,选择兼容性较好的通信方式。 性能:对于需要频繁通信的场景,选择性能较好的通信方式,避免影响用户体验。 在实际应用中,可能会结合使用多种通信方式,以满足不同的需求。 例如,可以使用Broadcast Channel进行实时通知,而使用LocalStorage进行简单的数据同步。

    Traverse The DOM

    Intro

    One of the most important skills of a web developer is DOM traversal and being able to select HTML elements with JavaScript. This will be a guide on my top 10 of the must know methods and hopefully this will help you master DOM traversal by the end of the guide. Fair warning! This is a guide for developers with at least some basic knowledge in HTML & JavaScript

    DOM Nodes

    Before we dive into the traversal methods, let’s look at the brief explanation of the DOM and Node Relationships from W3school. According to the W3C HTML DOM standard, everything in an HTML document is a node: -HTML node tree The entire document is a document node Every HTML element is an element node The text inside HTML elements are text nodes All comments are comment nodes

    Node Relationships

    The nodes in the node tree have a hierarchical relationship to each other. The terms parent, child, and sibling are used to describe the relationships. In a node tree, the top node is called the root (or root node) Every node has exactly one parent, except the root (which has no parent) A node can have a number of children Siblings (brothers or sisters) are nodes with the same parent

    Navigating Between Nodes

    Here’s a chart I drew up showing the following node properties to navigate between nodes -html mockup of profile cards with an image and some info parentNode previousSibling nextSibling firstChild lastChild childNodes[nodeNumber]

    Traversal Methods

    Before we get into the methods, below is a HTML node tree I drew up with a div representing a grandparent node which has two parent divs and finally each parent div has two children nodes each parent-1, parent-2 belongs to grandparent child-1, child-2 belongs to parent-1 child-3, child-4 belongs to parent-2 <body> <div class="grandparent" id="grandparent"> <!-- "parent-1" & "parent-2" belongs to "grandparent"--> <div class="parent" id="parent-1"> <!-- "child-1" & "child-2" belongs to "parent-1"--> <div class="child" id="child-1"> </div> <div class="child" id="child-2"> </div> </div> <div class="parent" id="parent-2"> <!-- "child-3" & "child-4" belongs to "parent-2"--> <div class="child" id="child-3"> </div> <div class="child" id="child-4"> </div> </div> </div> </body> getElementById - This one is a classic, find a single element node by targeting the id const grandparent = document.getElementById("grandparent") //or const parent2 = grandparent.getElementById("parent-2") 2. getElementsByClassName - This is our second classic way to select multiple elements at once, let’s say to target both our parent divs 3. querySelector - This is my favorite by far, a lot easier to use a single method to target classes or ids 4. querySelectorAll - similar to querySelector but used to select multiple element nodes 5. parentElement - used to target one level up the DOM tree to target the parent node 6. previousElementSibling - used to target one node to the left in terms of DOM tree 7. nextElementSibling - used to target one node to the right in terms of DOM tree 8. firstElementChild - used to target the first node down the DOM tree 9. lastElementChild - used to target the last node down the DOM tree 10. childNodes[node #] - last on my list but another one of my favorites, the childNodes method takes in a number to target child nodes of a parent

    DOM遍历 Traversal

    DOM 遍历是指在 HTML 文档中导航和定位元素的过程。 通过 DOM 遍历,您可以在文档中移动并查找特定的元素,以便对其进行操作或者检索信息。

    寻找子元素

    //DOM遍历 const h1 = document.querySelector('h1'); //寻找子元素 console.log(h1.querySelectorAll('.highlight')); 上面的代码说明可以通过DOM遍历快速的定位到子元素 我们也可以找到元素的所有子节点(包括元素节点、文本节点和注释节点)的 NodeList 对象 console.log(h1.childNodes); 我们也可以找到元素的所有子元素节点,不包括文本节点和注释节点。 这将返回一个 HTMLCollection 对象,其中包含所有子元素。 console.log(h1.children); 当然,我们可以通过这种寻找某个元素的子元素的方式来定义style h1.firstElementChild.style.color = 'white'; h1.lastElementChild.style.color = 'orangered';

    寻找父元素

    找到元素的父节点,无论父节点是什么类型的节点(元素节点、文本节点等)。 这将返回一个 Node 对象,表示 h1 元素的父节点。 console.log(h1.parentNode); 找到元素的最近的父元素节点。 如果 h1 的父节点是一个元素节点,则返回这个元素节点;如果 h1 没有父元素节点,则返回 null。 console.log(h1.parentElement); 使用 closest 方法来查找最接近的具有指定选择器的祖先元素,并为找到的元素设置背景颜色。 h1.closest('.header').style.background = 'var(--gradient-secondary)'; h1.closest('h1').style.background = 'var(--gradient-primary)';

    寻找兄弟元素

    打印出该前一个兄弟元素节点 console.log(h1.previousElementSibling); 说明向上没有兄弟元素,我们也可以往下找 console.log(h1.nextElementSibling); h1 元素的前一个兄弟节点和后一个兄弟节点,或者如果它们不存在则显示 null。 需要注意的是,这两个属性获取的节点可能是元素节点也可能是文本节点(或者其他类型的节点)。 console.log(h1.previousSibling); console.log(h1.nextSibling); 那我们怎么知道元素的所有兄弟元素呢,我们可以找父元素的所有子元素 console.log(h1.parentElement.children); 最后,我们来玩一下,将除h1元素的所有兄弟元素缩小一半 [...h1.parentElement.children].forEach(function(el) { if (el !== h1) el.style.transform = 'scale(0.5)'; });

    小技巧

    变量交换

    let a = 1, b = 2; [a, b] = [b, a]; // 输出:a = 2,b = 1

    对象解构

    const { name, age } = { name: "Riki", age: 22 }; // 输出:name = 'Riki', age = 22

    克隆对象

    当然这里是浅拷贝 const Obj = { name: "Riki", age: 22 }; const clonedObj = { ...Obj }; // 输出:clonedObj = {name: 'Riki', age: 22}

    合并对象

    const obj1 = { name: "Riki" }; const obj2 = { age: 22 }; const mergedObj = { ...obj1, ...obj2 }; // 输出:mergedObj = {name: 'Riki', age: 22}

    清理数组中的空值

    const arr = [0, 1, false, 2, "", 3]; const cleanedArray = arr.filter(Boolean); // 输出:cleanedArray = [1, 2, 3]

    将 NodeList 转换为数组

    const nodesArray = [...document.querySelectorAll("div")]; // 或者 const nodesArray = Array.form(document.querySelectorAll("div"));

    检查数组是否符合特定条件

    const arr = [1, 2, 3, -1, 4]; // 检查数组中是否有一项符合预期 const hasNegativeNumbers = arr.some((num) => num < 0); // 输出:hasNegativeNumbers = true // 检查数组中是否所有项符合预期 const allPositive = arr.every((num) => num > 0); //输出:allPositive = false

    将文本复制到剪贴板

    navigator.clipboard.writeText("要复制的文本");

    数组去重复

    const arr = [1, 2, 2, 3, 4, 4, 5]; const unique = [...new Set(arr)];

    查找数组的交集

    const arr1 = [1, 2, 3, 4]; const arr2 = [2, 4, 6, 8]; const intersection = arr1.filter((value) => arr2.includes(value)); // 输出:intersection = [2, 4]

    数组值的总和

    const arr = [1, 2, 3, 4]; const sum = arr.reduce((total, value) => total + value, 0); // 输出:sum = 10

    条件对象属性

    const condition = true; const value = "Hello World"; const newObject = { ...(condition && { key: value }) }; // 输出:newObject = { key: 'Hello World' }

    动态对象属性

    const dynamicKey = "name"; const value = "Riki Doe"; const obj = { [dynamicKey]: value }; // 输出:obj = { name: 'Riki Doe' }

    在线状态检查器

    const isOnline = navigator.onLine ? "Online" : "Offline"; // 输出:isOnline = 'Online'

    离开页面前确认

    window.onbeforeunload = () => "Are you sure you want to leave?";

    按键计算对象值之和

    const arrayOfObjects = [{ x: 1 }, { x: 2 }, { x: 3 }]; const sumBy = (arr, key) => arr.reduce((acc, obj) => acc + obj[key], 0); sumBy(arrayOfObjects, "x"); // 输出:6

    将 query string 解析为对象

    const query = "name=Riki&age=30"; const parseQuery = (query) => Object.fromEntries(new URLSearchParams(query)); // 输出:parseQuery = { name: 'Riki', age: '30' }

    将秒转换为时间字符串

    const seconds = 3661; const toTimeString = (seconds) => new Date(seconds * 1000).toISOString().substr(11, 8); toTimeString(seconds); // 输出:'01:01:01'

    对象中的最大值

    const scores = { math: 95, science: 99, english: 88 }; const maxObjectValue = (obj) => Math.max(...Object.values(obj)); maxObjectValue(scores); // 输出:99

    检查对象是否包含值

    const person = { name: "John", age: 30 }; const hasValue = (obj, value) => Object.values(obj).includes(value); hasValue(person, 30); // 输出:true

    有条件的修改项

    const scores = [45, 75, 62, 55, 90]; const updatedScores = scores.map((score) => (score < 60 ? score + 20 : score)); // 输出:updatedScores = [65, 75, 62, 75, 90]

    生成数组

    const range = Array.from({ length: 5 }, (_, i) => i + 1); // 输出:range = [1, 2, 3, 4, 5]

    超时请求

    const timeout = (promise, ms) => Promise.race([promise, new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), ms))]); timeout(fetch("https://api.riki.wang"), 5000) .then(() => "handleResponse") .catch(() => "handleError"); // 如果在指定的毫秒数内未返回,则拒绝并显示“超时”错误

    提取文件扩展名

    const fileName = "example.png"; const getFileExtension = (str) => str.slice(((str.lastIndexOf(".") - 1) >>> 0) + 2); // 输出:getFileExtension = 'png'

    检查 tab 是否激活

    const isTabFocused = () => document.hasFocus();

    切换元素的类名

    const element = document.querySelector(".my-element"); const toggleClass = (el, className) => el.classList.toggle(className); toggleClass(element, "active");

    实用技巧

    箭头函数

    箭头函数提供了一种简洁的语法,并在词法上绑定 this 值,简化函数声明。 function add() { return a + b; } // 箭头函数简介写法 const add = (a, b) => a + b;

    使用 let 和 const 代替 var

    避免使用 var 声明变量,使用 let 和 const 以确保块级作用域并避免提升问题。 对于不会重新分配的变量使用 const,对于需要重新分配的变量使用 let。 let name = 'CodeClear'; const age = 18

    解构赋值

    解构赋值方便从对象中提取属性值或从数组中提取值到独立的变量中。 // 对象提取属性值 const person = { name: 'CodeCler', age: 18}; const { name, age } = person; // 数组提取值 const numbers = [1, 2, 3]; const [ num1, num2 ] = numbers;

    展开运算符

    展开运算符允许你扩展可迭代对象(如数组)的元素或对象的属性。 const numbers = [1, 2, 3]; const newNumbers = [...numbers, 4, 5]; const person = { name: 'CodeClear' }; // 混合赋值 const newPerson = {...person, age: 18}

    模板字面量

    模板字面量提供了一种简单的方法将变量和表达式插入到字符串中,相较于原生字符串拼接增强代码可读性。 const name = 'CodeClear' const greeting = `Hello, ${name}!`

    默认参数

    为函数参数设置默认值以避免未定义错误。 function greet(name = 'CodeClear') { console.log(`Hello, ${name}!`) } greet() greet('Bob'

    剩余参数

    剩余参数允许你将不确定数量的参数表示为数组。 function sum(...numbers) { return numbers.reduce((a, b) => a + b, 0) } console.log(sum(1, 2, 3, 4, 5, 6)) // 21

    对象属性简写

    当属性名称和变量名称相同时,使用简写语法创建对象。 const name = 'CodeClear'; const age = 18; const person = { name, age }

    字符串方法

    使用现代字符串方法执行常见的字符串操作。 const str = 'Hello, World!'; console.log(str.includes('World')); // true console.log(str.startsWith('Hello')); // true console.log(str.endsWith('!')); // true

    短路运算符

    使用短路运算符进行条件表达式和默认值设置。 const user = { name: 'CodeClear' }; const name = user.name || 'Guest'; const isAdmin = user.isAdmin && 'Admin'

    Array.from()

    Array.from() 方法可用于将任何可迭代对象转换为数组。 const str = "Hello!"; const arr = Array.from(str); console.log(arr); //Output: ['H', 'e', 'l', 'l', 'o', '!'

    可选链

    可选链允许你在不检查每个引用是否有效的情况下安全地访问深层嵌套的属性。 const user = { name: 'CodeClear', address: { city: 'New York' } }; const city = user.address?.city;

    数组快速去重

    您可以使用 Set 从数组中删除重复元素,但是这种去重方式只能去除基本数据类型组成的数组。 const arr = [1, 2, 3, 4, 5, 6]; const arr2 = new Set(arr); const arr3 = [...arr2]

    空值合并运算符

    空值合并运算符 (??) 提供了一种在左操作数为 null 或未定义时返回右操作数的方法。 const user = { name: 'CodeClear' }; const name = user.name ?? 'Guest'

    数组方法

    用数组方法如 map(), filter(), 和 reduce() 以函数式的方式对数组进行常见操作。 const numbers = [1, 2, 3, 4, 5]; const doubled = numbers.map(num => num * 2); const evens = numbers.filter(num => num % 2 === 0); const sum = numbers.reduce((total, num) => total + num, 0);

    使用 for...of 进行迭代

    使用 for...of 循环更可读地迭代数组、字符串和其他可迭代对象。 const numbers = [1, 2, 3, 4, 5]; for (const number of numbers) { console.log(number); }

    克隆对象和数组

    使用展开运算符或 Object.assign() 克隆对象和数组。 const original = { name: 'CodeClear', age: 18 }; const clone = { ...original }; const arr = [1, 2, 3]; const arrClone = [...arr];

    动态属性名称

    使用动态属性名称动态设置对象属性。 const propName = 'age'; const person = { name: 'CodeClear', [propName]: 18 };

    防抖和节流

    通过防抖和节流优化频繁调用的函数,如滚动或调整大小事件。 防抖: function debounce(func, delay) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } window.addEventListener('resize', debounce(() => { console.log('Resized'); }, 300)); 节流: function throttle(func, limit) { let inThrottle; return function(...args) { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } window.addEventListener('scroll', throttle(() => { console.log('Scrolled'); }, 300));

    有效使用 console 进行调试

    利用各种 console 方法进行更有效的调试。 console.log('Simple log'); console.warn('This is a warning'); console.error('This is an error'); console.table([{ name: 'CodeClear', age: 18 }, { name: 'Jane', age: 25 }]); console.group('Group'); console.log('Message 1'); console.log('Message 2'); console.groupEnd();

    强制类型转换

    JavaScript是一种动态类型语言,这意味着变量可以在不同类型之间自由转换。

    什么是强制类型转换?

    强制类型转换(Coercion)是指将一种数据类型转换为另一种数据类型的过程。 在JavaScript中,这种转换可以是显式的(通过开发者明确调用转换函数)或隐式的(由JavaScript引擎自动进行)。

    三种基本类型转换

    JavaScript中的强制类型转换主要涉及三种基本类型:字符串、数字和布尔值。

     转换为字符串

    将值转换为字符串有多种方式,其中最常见的是通过调用String()函数或使用加号运算符(+)与空字符串相加。 let num = 123; let str = String(num); // 显式转换 let str2 = num + ''; // 隐式转换 console.log(str); // "123" console.log(str2); // "123"

     转换为数字

    将值转换为数字也有多种方式,可以使用Number()函数、加号运算符(+)、parseInt()或parseFloat()等。 let str = "456"; let num = Number(str); // 显式转换 let num2 = +str; // 隐式转换 console.log(num); // 456 console.log(num2); // 456 需要注意的是,parseInt()和parseFloat()用于解析字符串中的数字,但它们与Number()有所不同,因为它们不会处理非数值字符并且可以解析带有小数点的字符串。 let str = "3.14"; console.log(parseInt(str)); // 3 console.log(parseFloat(str)); // 3.14

     转换为布尔值

    所有值在JavaScript中都可以转换为布尔值。 JavaScript中有一些被认为是“假值”的值,它们转换为布尔值时会得到false,包括:0、-0、null、undefined、NaN和空字符串("")。 其他所有值都被认为是真值,转换为布尔值时会得到true。 console.log(Boolean(0)); // false console.log(Boolean("")); // false console.log(Boolean(null)); // false console.log(Boolean(undefined));// false console.log(Boolean(NaN)); // false console.log(Boolean(123)); // true console.log(Boolean("hello")); // true console.log(Boolean({})); // true

    常见的强制类型转换场景

     相等运算符(==)与严格相等运算符(===)

    在使用相等运算符(==)时,JavaScript会进行强制类型转换以比较不同类型的值。 相反,严格相等运算符(===)不会进行类型转换,只在两个值类型相同且值相等时返回true。 console.log(123 == "123"); // true,字符串"123"被转换为数字123 console.log(123 === "123"); // false,类型不同

     算术运算符

    当不同类型的值参与算术运算时,JavaScript会尝试将它们转换为数字。 let result = "5" - 3; // "5" 被转换为 5,结果为 2 console.log(result); // 2 result = "5" + 3; // 由于 + 运算符优先进行字符串连接,结果为 "53" console.log(result); // "53"

     逻辑运算符

    逻辑运算符(&&、||、!)也会触发类型转换。 它们通常会将操作数转换为布尔值,以决定运算结果。 console.log(!!"hello"); // true,非空字符串被转换为 true console.log(!!0); // false,0 被转换为 false console.log(null || "default"); // "default",null 被转换为 false

    避免强制类型转换的陷阱

    尽管强制类型转换在JavaScript中是常见且有用的,但它也可能导致意外行为。 因此,了解和避免这些陷阱是关键。

     NaN陷阱

    当尝试将非数值字符串转换为数字时,会得到NaN(Not-a-Number)。 let result = Number("hello"); console.log(result); // NaN

     null和undefined的特殊情况

    null和undefined在进行类型转换时有一些特殊的行为,需要特别注意。 console.log(Number(null)); // 0 console.log(Number(undefined)); // NaN

     字符串连接与算术运算

    由于+运算符既用于字符串连接又用于加法运算,容易引起混淆。 console.log("5" + 3); // "53",字符串连接 console.log("5" - 3); // 2,算术运算

    提升逻辑判断的可读性

    根据不同条件执行不同逻辑的场景,这样的逻辑判断可能会导致代码冗长且难以维护。

    初识逻辑判断的复杂性

    在 JavaScript 编程中,条件判断是非常常见的操作。 然而,当条件变得复杂时,代码中的 if/else 或 switch 语句会变得冗长且难以维护。 我们来看看下面这个例子: const handleButtonClick = (status) => { if (status === 1) { navigateTo('HomePage'); } else if (status === 2 || status === 3) { navigateTo('ErrorPage'); } else if (status === 4) { navigateTo('SuccessPage'); } else if (status === 5) { navigateTo('CancelPage'); } else { navigateTo('DefaultPage'); } } 在这个例子中,我们根据不同的状态码跳转到不同的页面。 虽然逻辑清晰,但随着条件的增加,代码会变得越来越臃肿和难以维护。 为了优化这种代码,我们需要探索更简洁的方法。

    利用 Switch 语句优化代码

    我们可以通过 switch 语句来优化上述代码,使其更易读: const handleButtonClick = (status) => { switch (status) { case 1: navigateTo('HomePage'); break; case 2: case 3: navigateTo('ErrorPage'); break; case 4: navigateTo('SuccessPage'); break; case 5: navigateTo('CancelPage'); break; default: navigateTo('DefaultPage'); } } 使用 switch 语句后,每种状态对应的处理逻辑更加直观,并且减少了重复代码。 通过 switch,我们可以在一个更结构化的方式中处理多种条件。 然而,随着条件的增加,switch 语句也会变得冗长。

    通过对象字面量提升代码可读性

    将条件判断放入对象中是一个非常有效的优化方式: const actions = { 1: 'HomePage', 2: 'ErrorPage', 3: 'ErrorPage', 4: 'SuccessPage', 5: 'CancelPage', default: 'DefaultPage', }; const handleButtonClick = (status) => { const action = actions[status] || actions.default; navigateTo(action); } 在这个示例中,我们使用对象的键值对来存储状态和对应的页面。 当按钮被点击时,通过访问对象属性来决定跳转到哪个页面。 这种写法不仅简洁,而且更容易维护和扩展。 我们可以通过对象的键值对快速找到对应的逻辑,而不需要写一大堆 if/else 或 switch 语句。

    引入 Map 对象进一步优化

    我们还可以利用 ES6 的 Map 对象来实现相同的功能,Map 对象的键可以是任意类型,使用起来更加灵活: const actions = new Map([ [1, 'HomePage'], [2, 'ErrorPage'], [3, 'ErrorPage'], [4, 'SuccessPage'], [5, 'CancelPage'], ['default', 'DefaultPage'], ]); const handleButtonClick = (status) => { const action = actions.get(status) || actions.get('default'); navigateTo(action); } Map 对象允许使用任意类型的值作为键,这使得我们的代码更加灵活。 我们可以通过调用 actions.get(status) 来获取对应的页面路径。 如果状态值不存在,我们可以使用 actions.get('default') 获取默认值。 这种方式不仅简洁,还可以避免一些键值对的冲突问题。

    处理多条件判断

    当我们的逻辑升级为二元判断时,代码量会急剧增加,例如: const handleButtonClick = (status, role) => { if (role === 'guest') { if (status === 1) { // do something for guest } else if (status === 2) { // do something for guest } // ... more conditions } else if (role === 'admin') { if (status === 1) { // do something for admin } else if (status === 2) { // do something for admin } // ... more conditions } } 当有多个条件时,代码的复杂性会进一步增加。 为了简化代码,我们可以通过 Map 并将条件拼接成字符串作为键: const actions = new Map([ ['guest_1', () => { /* do something for guest and status 1 */ }], ['guest_2', () => { /* do something for guest and status 2 */ }], // ... more mappings ['admin_1', () => { /* do something for admin and status 1 */ }], ['admin_2', () => { /* do something for admin and status 2 */ }], ['default', () => { /* default action */ }], ]); const handleButtonClick = (role, status) => { const action = actions.get(`${role}_${status}`) || actions.get('default'); action(); } 我们通过拼接字符串将角色和状态组合成键,并在 Map 中查找对应的处理函数。 这种方式使代码更加简洁,易于维护和扩展。 每个组合键对应一个特定的处理函数,避免了嵌套的 if/else 或 switch 语句。

    使用对象作为 Map 的键

    如果将查询条件拼接成字符串感觉不太优雅,可以使用对象作为 Map 的键: const actions = new Map([ [{ identity: 'guest', status: 1 }, () => { console.log('Guest, status 1'); }], [{ identity: 'guest', status: 2 }, () => { console.log('Guest, status 2'); }], [{ identity: 'admin', status: 1 }, () => { console.log('Admin, status 1'); }], //... ]); const handleButtonClick = (identity, status) => { // 将 Map 对象转换为数组并查找匹配的键值对 const action = [...actions].find(([key]) => key.identity === identity && key.status === status); if (action) { // action[1] 是找到的键值对中的值(处理函数) action[1](); } else { console.log('Default action'); } } // 测试调用 handleButtonClick('guest', 1); // 输出: Guest, status 1 handleButtonClick('admin', 1); // 输出: Admin, status 1 handleButtonClick('guest', 3); // 输出: Default action 在这个例子中,我们将条件组合成对象,并使用这些对象作为 Map 的键。 通过 find 方法,我们可以查找符合条件的键值对,并执行对应的处理函数。 这种方法使代码更具可读性,并且更容易管理复杂的条件判断。

    使用正则表达式处理复杂条件

    假设在某些场景下,我们需要在同一个身份下处理多个相同状态的逻辑,例如,对于 guest 的 status 1 到 4 处理逻辑相同,status 5 的处理逻辑不同: const actions = () => { const functionA = () => { console.log('Guest, status 1-4'); }; const functionB = () => { console.log('Guest, status 5'); }; return new Map([ [{ identity: 'guest', status: 1 }, functionA], [{ identity: 'guest', status: 2 }, functionA], [{ identity: 'guest', status: 3 }, functionA], [{ identity: 'guest', status: 4 }, functionA], [{ identity: 'guest', status: 5 }, functionB], //... ]); } const handleButtonClick = (identity, status) => { const action = [...actions()].find(([key]) => key.identity === identity && key.status === status); if (action) { action[1](); } else { console.log('Default action'); } } // 测试调用 handleButtonClick('guest', 1); // 输出: Guest, status 1-4 handleButtonClick('guest', 5); // 输出: Guest, status 5 handleButtonClick('admin', 1); // 输出: Default action 这种方法虽然能解决问题,但需要重复定义多个相同的逻辑。 为了减少重复代码,可以利用正则表达式: const actions = () => { const functionA = () => { console.log('Guest, status 1-4'); }; const functionB = () => { console.log('Guest, status 5'); }; return new Map([ [/^guest_[1-4]$/, functionA], [/^guest_5$/, functionB], //... ]); } const handleButtonClick = (identity, status) => { const action = [...actions()].find(([key]) => key instanceof RegExp && key.test(`${identity}_${status}`)); if (action) { action[1](); } else { console.log('Default action'); } } // 测试调用 handleButtonClick('guest', 2); // 输出: Guest, status 1-4 handleButtonClick('guest', 5); // 输出: Guest, status 5 handleButtonClick('admin', 3); // 输出: Default action 使用正则表达式作为键,我们可以更高效地处理多个相同逻辑的条件,避免重复定义相同的处理函数。 这种方法不仅减少了代码量,还使得代码更具可读性和可维护性。

    HTML DOM createObjectURL() method

    The createObjectURL() method creates a DOMString containing a URL representing the object given in the parameter of the method. The new object URL represents the specified File object or Blob object. Note: The URL lifetime is tied to the document in which it was created and To release an object URL, call revokeObjectURL().

    Syntax:

    const url = URL.createObjectURL(object); Usage: When using createObjectURL() in your code, remember to call URL.revokeObjectURL() for each object URL created when it’s no longer needed. This helps manage memory efficiently. While browsers release object URLs automatically when the document is unloaded, manually revoking them at safe times can improve performance and reduce memory usage. Example: In this example, we will create an object URL for the image object using this method. html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>URL.createObjectURL example</title> </head> <body> <input type="file"> <img> <p class="p">The URL of this image is : </p> </body> <script> let Element = document.querySelector('input'); let img = document.querySelector('img'); Element.addEventListener('change', function() { let url = URL.createObjectURL(Element.files[0]); img.src = url; console.log(url); let d = document.querySelector(".p"); d.textContent += url; }); </script> </html> Output next() function JavaScript AsyncGenerator.prototype.next() method is used with the asynchronous generators to retrieve the next value in the sequence produced by the generator. It returns a Promise that resolves to the object with two properties: value and done. Syntax: AsyncGenerator.prototype.next(value); The below examples will explain the practical implementation of the AsyncGenerator.prototype.next() method. Example 1: create a generator function and then use the next() method on it by creating an instance of it. async function* asyncGenerator() { yield 3; yield 5; yield 3; } const generator = asyncGenerator(); generator.next().then(result => { console.log(result.value); console.log(result.done); }); generator.next().then(result => { console.log(result.value); console.log(result.done); }); generator.next().then(result => { console.log(result.value); console.log(result.done); }); Output 3 false 5 false 3 false Example 2: This example will illustrate the use of the asyncGenerator function and the next() method with the string values. async function* asyncGenerator() { yield 'HI'; yield 'Async'; yield 'Generator'; } const generator = asyncGenerator(); generator.next().then(result => { console.log(result.value); console.log(result.done); }); generator.next().then(result => { console.log(result.value); console.log(result.done); }); generator.next().then(result => { console.log(result.value); console.log(result.done); }); Output HI false Async false Generator false

    HTML5 Audio to play a playlist of local mp3

    <input type="file" id="songs" multiple> <audio controls id="myAudio" autoplay></audio> var songs = document.getElementById("songs"), myAudio = document.getElementById("myAudio"); thenextItem = 0 files = ["a.mp3". "b.mp3"] len = files.length; myAudio.addEventListener("ended", function(){ thenextItem += 1; playSong(thenextItem); console.log(len, thenextItem); if((len-1)==thenextItem){ thenextItem=-1; } }); function playSong(n){ var url = URL.createObjectURL(files[n]); myAudio.setAttribute('src', url); myAudio.play(); } example ok: thenextItem = 0 allMusicNames = ['1979 抉擇 .mp3', 'black tape.mp3', 'bodypainting.mp3', 'DEEP STRETCHING.mp3', 'fashionMusic.mp3', 'GreenLeaves.mp3', 'ideas.mp3', 'Jeans.mp3', 'lowBeep.mp3', 'Meditation Music.mp3', 'Miami Swim.mp3', 'pig.mp3', 'Spirit of Harp.mp3', 'Stepping into the Ether.mp3', 'stringVibrate.mp3', 'swim2022.mp3', 'The Sound of Silence.mp3', 'toneBeep.mp3', 'Yellow & blue.mp3', '一生所爱.mp3', '一眼忧伤.mp3', '不了情.mp3', '世界由我造.mp3', '之子于歸.mp3', '倩女幽魂.mp3', '倩影.mp3', '兩忘煙水裡.mp3', '兩生契.mp3', '又见逍遥.mp3', '吴侬软语花妖.mp3', '唢呐断肠.mp3', '复活节.mp3', '大丈夫.mp3', '大俠霍元甲.mp3', '大內群英.mp3', '大刀王五.mp3', '天蠶變 .mp3', '太極張三豐.mp3', '子衿.mp3', '小刀会.mp3', '小提琴 陈情令 无羁.mp3', '少女慈禧.mp3', '幽狐.mp3', '徐小鳳 人似浪花.mp3', '我住長江頭.mp3', '擊鼓.mp3', '春江花月夜.mp3', '春雨彎刀.mp3', '曾路得 天各一方.mp3', '梁凱莉《癡雲》.mp3', '梁祝.mp3', '楚国八百年.mp3', '楚國情歌.mp3', '此恨何时休.mp3', '此生长.mp3', '殇 大提琴版.mp3', '每當變幻時.mp3', '江南春色.mp3', '沧海一声笑.mp3', '清溪潺流.mp3', '游牧时光.mp3', '王琪.mp3', '琵琶吟.mp3', '琵琶语.mp3', '痴情冢.mp3', '石莉娟 二泉映月.mp3', '秋戀.mp3', '程桂蘭 二泉映月.mp3', '空山静.mp3', '管子演奏.mp3', '翡翠劇場 - 風雲.mp3', '葉振棠.mp3', '葬花吟.mp3', '蒹葭.mp3', '誰能明白我.mp3', '跳灰.mp3', '追憶.mp3', '追梦人.mp3', '醉梦 陈悦.mp3', '钢琴梁祝.mp3', '關正傑 - 天蠶變.mp3', '陶笛 森林狂想曲.mp3', '雨碎江南.mp3', '齊豫 - 橄欖樹.mp3',] len = allMusicNames.length; myAudio.addEventListener("ended", function(){ thenextItem = Math.floor(Math.random() * (len -1)); url = "D:\\Dropbox\\Public\\LibDocs\\mp3\\"+ allMusicNames[thenextItem]; myAudio.src = url; myAudio.load(); myAudio.play(); myAudio.volume = 0.05; }); // init thenextItem = Math.floor(Math.random() * (len -1)); url = "D:\\Dropbox\\Public\\LibDocs\\mp3\\"+ allMusicNames[thenextItem]; myAudio.src = url; myAudio.load(); myAudio.volume = 0.05; example modified for delay action: var allMusicNames = ['1979 抉擇 .mp3', 'black tape.mp3', 'bodypainting.mp3', 'DEEP STRETCHING.mp3', 'fashionMusic.mp3', 'GreenLeaves.mp3', 'ideas.mp3', 'Jeans.mp3', 'lowBeep.mp3', 'Meditation Music.mp3', 'Miami Swim.mp3', 'pig.mp3', 'Spirit of Harp.mp3', 'Stepping into the Ether.mp3', 'stringVibrate.mp3', 'swim2022.mp3', 'The Sound of Silence.mp3', 'toneBeep.mp3', 'Yellow & blue.mp3', '一生所爱.mp3', '一眼忧伤.mp3', '不了情.mp3', '世界由我造.mp3', '之子于歸.mp3', '倩女幽魂.mp3', '倩影.mp3', '兩忘煙水裡.mp3', '兩生契.mp3', '又见逍遥.mp3', '吴侬软语花妖.mp3', '唢呐断肠.mp3', '复活节.mp3', '大丈夫.mp3', '大俠霍元甲.mp3', '大內群英.mp3', '大刀王五.mp3', '天蠶變 .mp3', '太極張三豐.mp3', '子衿.mp3', '小刀会.mp3', '小提琴 陈情令 无羁.mp3', '少女慈禧.mp3', '幽狐.mp3', '徐小鳳 人似浪花.mp3', '我住長江頭.mp3', '擊鼓.mp3', '春江花月夜.mp3', '春雨彎刀.mp3', '曾路得 天各一方.mp3', '梁凱莉《癡雲》.mp3', '梁祝.mp3', '楚国八百年.mp3', '楚國情歌.mp3', '此恨何时休.mp3', '此生长.mp3', '殇 大提琴版.mp3', '每當變幻時.mp3', '江南春色.mp3', '沧海一声笑.mp3', '清溪潺流.mp3', '游牧时光.mp3', '王琪.mp3', '琵琶吟.mp3', '琵琶语.mp3', '痴情冢.mp3', '石莉娟 二泉映月.mp3', '秋戀.mp3', '程桂蘭 二泉映月.mp3', '空山静.mp3', '管子演奏.mp3', '翡翠劇場 - 風雲.mp3', '葉振棠.mp3', '葬花吟.mp3', '蒹葭.mp3', '誰能明白我.mp3', '跳灰.mp3', '追憶.mp3', '追梦人.mp3', '醉梦 陈悦.mp3', '钢琴梁祝.mp3', '關正傑 - 天蠶變.mp3', '陶笛 森林狂想曲.mp3', '雨碎江南.mp3', '齊豫 - 橄欖樹.mp3',] var options = ''; // build the List select option listlen = allMusicNames.length; for (var i = 0; i < listlen; i++) { options += ''; } $("#selectList").html(options); function changeAudioSource(source) { selectElement = document.getElementById('selectList'); selectedOption = selectElement.value; console.log('Selected option: ' + selectedOption); myaudio.src = selectedOption; myaudio.load(); myaudio.play(); myaudio.volume = 0.05; } window.onload=function(){ // init thenextItem = Math.floor(Math.random() * (listlen -1)); url = "D:\\Dropbox\\Public\\LibDocs\\mp3\\"+ allMusicNames[thenextItem]; myaudio = document.getElementById('myaudio'); myaudio.addEventListener("ended", function(){ thenextItem = Math.floor(Math.random() * (listlen -1)); url = "D:\\Dropbox\\Public\\LibDocs\\mp3\\"+ allMusicNames[thenextItem]; console.log(url) myaudio.src = url; myaudio.load(); myaudio.play(); myaudio.volume = 0.05; }); myaudio.setAttribute('src', url); myaudio.load(); myaudio.volume = 0.05; myaudio.play(); }

    html5 loading lazy

    <img src="URL" loading="eager|lazy"> <iframe loading="lazy" src="video-player.html" title="..."></iframe> eager Default. Loads an image immediately lazy Defer loading of images until some conditions are met

    get Current location Domain Name

    locationUrl = location.href CurrentDomainName = window.location.hostname if(CurrentDomainName != 'williamkpchan.github.io'){ urlHeader = 'D:/Dropbox/Public/LibDocs/mp3/' }else{ urlHeader = '' }

    Timesheet.js时间表库

    Timesheet.js 用于创建时间表。 功能特点简洁的 API。 • 高度可定制化:通过 CSS 样式调整进行定制。 • 轻量化

    快速开始

    由于 Timesheet.js 不支持 npm 引入,从 github 中下载源码引入到项目中。 <link rel="stylesheet" href="./libs/timesheet.js/dist/timesheet.min.css" /> <div id="app"> <div id="timesheet"></div> </div> <script src="./libs/timesheet.js/dist/timesheet.min.js"></script> <script> const timesheet = new Timesheet('timesheet', 2000, 2020, [ ['09/2000', '07/2006', '某某小学', 'default'], ['09/2006', '07/2009', '某某初级中学', 'ipsum'], ['09/2009', '07/2012', '某某高级中学', 'dolor'], ['09/2012', '07/2016', '清华大学', 'lorem'], ]) </script> ['09/2012', '07/2016', '清华大学', 'lorem'], 其中参数, 开始时间: 支持日期格式,例如:2002 、02/2012 ; 结束时间; 标题; 配色:取值 default 红色,lorem 绿色、ipsum 蓝色、dolor 黄色、sit 青色。

    应用场景

    个人简历网站:展示个人的工作经历和项目周期,使简历更加直观和具有吸引力。 历史事件展示:制作互动式的历史时间线,通过 Timesheet.js 展示不同历史事件的发生时间,增加用户互动体验。 • 教育应用:在教育相关的网站或应用中,使用 Timesheet.js 展示课程安排或学术研究的时间序列,帮助学生更好地规划学习进度。 • 数据分析:将时间相关的数据通过 Timesheet.js 进行可视化展示,便于分析和理解数据随时间的变化趋势。

    总结

    Timesheet.js 是一个简单易用的工具,让你的在不需要复杂编码的情况下创建一个美观的时间轴展示。

    引用链接

    https://github.com/sbstjn/timesheet.js

    如何获取 blob里面的值

    要从Blob对象中获取其内容需要根据Blob的内容类型采取不同的策略。

    1.1. JSON 数据

    如果Blob包含的是JSON格式的数据,你可以使用TextDecoder来读取它,并将其解析为JSON。 const blob = new Blob([/* ... */], { type: 'application/json' }); // 创建一个读取器 const reader = new FileReader(); reader.onloadend = function() { const jsonContent = this.result; // 这里是字符串形式的JSON try { const jsonData = JSON.parse(jsonContent); console.log(jsonData); // 解析后的JSON对象 } catch (error) { console.error('Error parsing JSON', error); } }; reader.readAsText(blob); // 读取Blob作为文本

    1.2. 文本数据

    如果Blob包含的是普通的文本数据,同样可以使用FileReader的readAsText方法。 const blob = new Blob([/* ... */], { type: 'text/plain' }); const reader = new FileReader(); reader.onloadend = function() { const textContent = this.result; console.log(textContent); // 文本内容 }; reader.readAsText(blob); // 读取Blob作为文本

    1.3. 图像数据

    如果Blob包含的是图像数据,你可以使用URL.createObjectURL来创建一个临时的URL,然后在<img>标签中显示这个URL。 const blob = new Blob([/* ... */], { type: 'image/jpeg' }); const imageUrl = URL.createObjectURL(blob); const imgElement = document.createElement('img'); imgElement.src = imageUrl; document.body.appendChild(imgElement); // 显示图像

    1.4. 其他二进制数据

    对于其他类型的二进制数据,可以使用readAsArrayBuffer方法来读取。 const blob = new Blob([/* ... */], { type: 'application/octet-stream' }); const reader = new FileReader(); reader.onloadend = function() { const arrayBuffer = this.result; // 在这里可以使用arrayBuffer进行进一步处理 // 比如转换为Uint8Array或其他形式 }; reader.readAsArrayBuffer(blob);

    1.5. 示例

    假设你有一个fetch请求返回了一个Blob对象,你可以这样处理: fetch('/your-endpoint') .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.blob(); // 获取Blob对象 }) .then(blob => { // 根据Content-Type确定如何处理 if (blob.type.startsWith('application/json')) { // 处理JSON数据 const reader = new FileReader(); reader.onloadend = () => { const jsonContent = reader.result; const jsonData = JSON.parse(jsonContent); console.log(jsonData); }; reader.readAsText(blob); } else if (blob.type.startsWith('image/')) { // 处理图像数据 const imageUrl = URL.createObjectURL(blob); const imgElement = document.createElement('img'); imgElement.src = imageUrl; document.body.appendChild(imgElement); } else if (blob.type === 'text/plain') { // 处理纯文本数据 const reader = new FileReader(); reader.onloadend = () => { const textContent = reader.result; console.log(textContent); }; reader.readAsText(blob); } else { // 处理其他类型的数据 const reader = new FileReader(); reader.onloadend = () => { const arrayBuffer = reader.result; console.log(new Uint8Array(arrayBuffer)); // 以Uint8Array的形式显示数据 }; reader.readAsArrayBuffer(blob); } }) .catch(error => console.error('There has been a problem with your fetch operation:', error)); 请注意,在处理完Blob之后,记得释放创建的临时URL以避免内存泄漏: // 当不再需要时 URL.revokeObjectURL(imageUrl);

    CSS, JavaScript 让进度条不再单调

    超越传统的半圆形进度条

    一个优美的半圆形设计。 它使用ProgressBar.js和SVG,为进度显示带来了更加吸引人的视觉效果。 源码:https://codepen.io/andrewsims/pen/ExroZjM

    简洁实用的下载进度动画

    源码:https://codepen.io/aaroniker/pen/ZEYmPqM

    创意十足的进度条动画

    源码:https://codepen.io/evawythien/pen/jegRxN

    独特的时间进度时钟

    源码: https://codepen.io/jkantner/pen/MWEmExB

    纯CSS的订单处理步骤

    源码: https://codepen.io/jcoulterdesign/pen/zdwajv

    滚动式进度条

    源码: https://codepen.io/thomasvaeth/pen/XZQWMW

    响应式圆形进度条

    源码: https://codepen.io/tiggr/pen/VwwZoOR

    旋转3D进度条

    源码: https://codepen.io/ghaste/pen/XWLJWvK

    Chroma.js 颜色处理库

    Chroma.js, 一个小巧而强大的 JavaScript 库 功能特性 •颜色空间转换:Chroma.js 支持包括 RGB、HEX、HSL、HSV、LAB、LCH、XYZ 以及 CMYK 在内的颜色空间之间的无缝转换。 • 动态颜色操作:提供了颜色变暗、变亮等动态调整功能,以适应不同的视觉需求。 • 渐变效果生成:能够创建平滑且吸引人的颜色渐变效果,为数据可视化增添视觉吸引力。 • 调色板构建:允许用户构建和管理个性化的颜色调色板,简化颜色使用流程。 • 与 d3.js 的兼容性:Chroma.js 可与流行的数据可视化库 d3.js 无缝集成,扩展其功能。

    快速开始

    通过 npm 包管理器安装 Chroma.js,或通过在 HTML 文件中引入 CDN 链接来快速集成。 创建 Chroma 对象并利用其丰富的 API,用户可以轻松实现颜色的转换与操作。 npm install chroma-js Chroma.js 中最基础的操作包括颜色的创建、转换和其他颜色空间的转换。 创建一个 Chroma 对象,然后将其转换为其他颜色格式: import chroma from "chroma-js" const color = chroma('#3498db'); // 创建一个颜色对象 console.log(color.hex()); // 输出: #3498db console.log(color.rgb()); // 输出: [52, 152, 219] console.log(color.hsl()); // 输出: [204, 0.68, 0.53] 除了颜色转换,Chroma.js 还提供了多种颜色操作方法,比如调整亮度、混合颜色、生成渐变色等: let color1 = chroma('#ff0000').brighten(2); // 提高亮度 let color2 = chroma.mix('#ff0000', '#0000ff'); // 混合红色和蓝色 console.log(color1.hex()); // 输出: 根据实际调整结果变化 console.log(color2.hex()); // 输出: 根据实际调整结果变化 Chroma.js 还可以生成漂亮的颜色渐变,数据可视化比较常用: let scale = chroma.scale(['white', 'red']); console.log(scale(0.5).hex()); // 输出: "#ff8080",介于白色和红色中间的颜色

    CSS 和 JavaScript 时间线设计

    时间线可以简洁、生动地展示内容。

    聚焦历史事件

    源码: https://codepen.io/stefan-kyurkchiev/pen/NZGmJB

    博客文章时间线

    时间线不仅可以用来展示历史事件,还可以用于按时间顺序排列的内容展示,比如博客文章。 源码: https://codepen.io/Tracy_Tung/pen/XLmyaZ

    多功能的视图切换

    可以通过键盘、拖动或点击来浏览时间线,还可以自由放大或缩小内容,并快速回到时间线的起点。 源码: https://codepen.io/sgroff04/pen/JOLrGd

    独特的时间线

    高瘦的面板。 将鼠标悬停在面板上时,会出现全彩色的图片和文本。 源码: https://codepen.io/elaleph23/pen/ZNBMJZ

    滚动式

    源码: https://codepen.io/tns301/pen/yaboKX

    简约实用的时间线

    源码: https://codepen.io/adhitamafikri/pen/PaxEMR

    Node.js后端利器 Hapi.js

    Hapi.js(简称Hapi)是一个用于构建应用程序和服务的丰富框架,基于Node.js。 Hapi.js 提供了一系列内置的功能,让你不再需要频繁依赖第三方插件,简化了开发流程。

    Hapi.js的使用方式

    Hapi.js的安装和使用非常简单,你只需要安装它并写几行代码就能启动一个服务器。 以下是一个简单的示例: // 安装Hapi.js // npm install @hapi/hapi // 引入Hapi.js const Hapi = require('@hapi/hapi'); // 创建服务器实例 const init = async () => { const server = Hapi.server({ port: 3000, host: 'localhost' }); // 定义一个简单的路由 server.route({ method: 'GET', path: '/', handler: (request, h) => { return { hello: 'world' }; } }); // 启动服务器 await server.start(); console.log('Server running on %s', server.info.uri); }; process.on('unhandledRejection', (err) => { console.log(err); process.exit(1); }); init();

    Hapi.js的优劣势

    功能强大:包括验证、路由、插件系统等,减少了对第三方库的依赖。 劣势: 学习曲线:由于功能丰富且高度可配置,对新手来说可能需要一些时间来熟悉。 重量级:相比于一些轻量级框架,Hapi.js的功能和配置可能显得有些“重”。 性能负担:虽然Hapi.js性能不错,但在极高并发场景下,可能仍需要额外的性能优化。

    7. 使用Hapi.js需要注意的地方

    版本兼容性:确保所使用的插件版本和Hapi.js主版本匹配,避免依赖冲突。 性能优化:在高并发场景下,依然需要进行性能调优,比如使用缓存和负载均衡。 安全配置:应用默认的安全配置,并根据需求进行调整,确保应用的安全性。

    无限滚动网格库 InfiniteGrid

    InfiniteGrid 是什么? 允许开发者创建各种类型的网格布局,如瀑布流、整齐排列或框架布局,并支持多平台,包括桌面端、移动端以及主流前端框架的集成,如 Angular、React、Vue 和 Svelte。 InfiniteGrid 的核心在于其高效的 DOM 管理和性能优化策略,通过维持较低的 DOM 数量来保证流畅的用户体验,即使在元素大小不一的情况下也能快速响应。

    核心功能

     网格类型

    InfiniteGrid 支持多种布局类型,包括 MasonryInfiniteGrid(瀑布流布局)、JustifiedInfiniteGrid、FrameInfiniteGrid 和 PackingInfiniteGrid,适用于不同的展示需求。 MasonryInfiniteGrid MasonryInfiniteGrid 是一种网格,用于堆叠与一堆砖块宽度相同的项目。 将所有图像的宽度调整为相同大小,找到高度最低的列,然后插入新项目。 JustifiedInfiniteGrid “justified”是一个印刷术语,意思是“它适合一行宽”。 JustifiedGrid 是根据给定大小的线填充项目的网格。 stretch基本上可以打破项目的比例并拉伸内联尺寸以填充容器。 如果将sizeRange范围设置得窄,则可以很好地拉伸。 FrameInfiniteGrid “框架”是一个印刷术语,意思是“它适合一行宽”。 FrameGrid 是在给定尺寸的线条的基础上填充项目的网格。 PackingInfiniteGrid

     框架融合

    InfiniteGrid 支持多种前端框架,如 Angular、React、Vue、Svelte 等,易于集成到现有的项目中 。 • @egjs/vue3-infiniteGrid • @egjs/react-infiniteGrid

    快速开始

    InfiniteGrid 提供了多种安装方式 npm 或 yarn、CDN 等方式。 npm install --save @egjs/infinitegrid # CDN 引入 <script src="https://unpkg.com/@egjs/infinitegrid/dist/infinitegrid.min.js"></script> 定义容器 DOM 元素 <div class="container"></div> 通过 ES 模块引入到项目中。 // 导入 MasonryInfiniteGrid 类,它是 @egjs/infinitegrid 库的一部分,用于创建瀑布流布局。 import { MasonryInfiniteGrid } from "@egjs/infinitegrid"; // 定义 getItems 函数,它生成一组新的项目元素。 function getItems(nextGroupKey, count) { const nextItems = []; // 初始化一个空数组来存放生成的项目。 // 循环创建 count 个项目。 for (let i = 0; i < count; ++i) { const num = nextGroupKey * count + i; // 计算每个项目的编号。 nextItems.push(`<div class="item"></div>`); // 将一个新项目添加到数组中。 } return nextItems; // 返回生成的项目数组。 } // 创建 MasonryInfiniteGrid 实例,并设置其容器为拥有 ".container" 选择器的元素,以及设置间隔为 5px。 const ig = new MasonryInfiniteGrid(".container", { gap: 5, }); // 监听 "requestAppend" 事件,当需要追加新内容时触发。 ig.on("requestAppend", (e) => { // 计算下一个组的键值,如果 e.groupKey 是 undefined,则默认为 0,然后加 1。 const nextGroupKey = (+e.groupKey || 0) + 1; // 调用 append 方法,传入新生成的项目数组和组键,以追加到网格布局中。 ig.append(getItems(nextGroupKey, 10), nextGroupKey); }); // 调用 renderItems 方法来渲染初始的项目。 ig.renderItems(); 实现了一个基本的无限滚动功能,当用户滚动到页面底部时,会自动加载更多的项目。 getItems 函数用于生成新的项目,requestAppend 事件监听器用于在需要时追加新项目。 ig.renderItems() 用于初始化渲染项目。

    Reduce进阶用法

     基本语法

    array.reduce(function(total, currentValue, currentIndex, arr), initialValue) array:你要操作的数组。 function:用来处理数组每个元素的回调函数。 initialValue:可选的初始值,可以不写。 具体点说,回调函数里有这些参数: total:累计值。 第一次是初始值,之后是上一次循环的结果。 currentValue:当前处理的数组元素。 currentIndex:当前元素的索引,通常用不到,可以忽略。 arr:当前正在处理的整个数组,也可以忽略。

     工作流程

    理解这些参数后,我们来看reduce是怎么工作的: 设置初始值:如果你给了initialValue,它会作为total的初始值;如果没给,数组的第一个元素会作为初始值。 迭代处理:reduce从初始值开始(或者数组的第一个/第二个元素),逐个处理每个currentValue,并把结果累加到total。 完成迭代:数组处理完了,reduce就会返回累加后的最终结果。

     举个简单的例子

    假设你有一个数组[1, 2, 3, 4],你想算出这个数组中所有数字的和: const sum = [1, 2, 3, 4].reduce(function(total, currentValue) { return total + currentValue; }, 0); console.log(sum); // 输出:10 看,这段代码就是在做加法,reduce从0开始,每次把当前数字加到total上,最后得到10。

    基础示例

    reduce方法在JavaScript中就像一个万能的工具箱,可以帮你轻松完成各种任务。

     场景1:计算数组的总和

    想象一下,你是一名超市收银员,顾客买了一堆东西,现在需要计算总价。 你拿着收银机(reduce方法),每扫描一个商品的价格(数组中的每个数字),就把它累加到总金额中。 最后,你告诉顾客一共需要多少钱。 代码如下: const prices = [5, 12, 3, 7, 10]; const totalAmount = prices.reduce((total, price) => total + price, 0); console.log(totalAmount); // 输出:37 这里reduce就是在帮你“算账”,它从0开始,每次加上一个商品的价格,最后得到总金额37。

     场景2:数组元素的拼接

    假设你在写一首歌的歌词,每个词就像一颗珍珠,你需要把它们串成一句完整的话。 reduce在这里就像一根线,把这些珍珠一个一个串起来,最终形成了一串美丽的项链。 代码如下: const lyrics = ["I", "love", "coding", "with", "JavaScript"]; const sentence = lyrics.reduce((total, word) => total + " " + word); console.log(sentence); // 输出:"I love coding with JavaScript" 在这个例子中,reduce把每个词拼接在一起,最终形成了这句优美的话:"I love coding with JavaScript"。

     场景3:找到数组中的最大值

    想象你在组织一次班级选拔赛,想找出谁是班里的“最强王者”。 每当有一个新同学(currentValue)登场时,你都要和现任“王者”(total)比一比,看谁更强,最终挑出那个真正的“王者”。 代码如下: const scores = [45, 85, 72, 93, 66]; const highestScore = scores.reduce((max, score) => Math.max(max, score), -Infinity); console.log(highestScore); // 输出:93 在这个比喻中,reduce方法帮你把所有同学的分数都比了一遍,最后选出分数最高的那个,成为“最强王者”。

    进阶用法

    JavaScript的reduce方法不仅能处理基础的数组操作,在实际业务场景中,它还能帮你解决很多复杂的问题。 接下来,我们将通过具体的业务场景,结合一些代码示例,来帮助你更好地理解这些高级用法。

     1. 扁平化数组

    想象你有一个装满了小盒子的大盒子,而这些小盒子里又装着更小的盒子。 你的任务是把所有的小盒子里的物品全部倒出来,放到一个平面上,这样你可以一眼看到所有物品。 这就是我们要做的“扁平化”操作。 function Flat(arr = []) { return arr.reduce((total, currentValue) => total.concat(Array.isArray(currentValue) ? Flat(currentValue) : currentValue), []); } const nestedFiles = [0, 1, [2, 3], [4, 5, [6, 7]], [8, [9, 10, [11, 12]]]]; console.log(Flat(nestedFiles)); // 输出:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] reduce:就像把大盒子一层层打开。 Array.isArray(currentValue):检查当前拿到的是否还是一个小盒子(数组)。 Flat(currentValue):如果是小盒子,再递归地把它打开,直到拿出所有物品(非数组元素)。 concat:把这些物品一个个放到我们铺开的平面上(结果数组)。

     2. 分割数组——分页显示商品列表

    想象你在打包一批商品,每个包裹只能装固定数量的商品。 当一个包裹装满时,你就开始打包下一个包裹。 最终,你会得到一系列整齐的包裹,每个包裹里都有固定数量的商品。 这就是我们要做的“分页显示”。 function Chunk(arr, size) { return arr.length ? arr.reduce((total, currentValue) => (total[total.length - 1].length === size ? total.push([currentValue]) : total[total.length - 1].push(currentValue), total), [[]]) : []; } const products = [1, 2, 3, 4, 5]; console.log(Chunk(products, 2)); // 输出:[[1, 2], [3, 4], [5]] reduce:就像在打包商品。 total[total.length - 1]:这是当前正在打包的包裹。 total[total.length - 1].length === size:检查当前包裹是否装满。 push:如果满了,开始一个新的包裹;如果没满,把商品继续装入当前包裹。

     3. 统计出现次数

    想象你在统计每个用户点击了多少次按钮,就像在记录每个用户按下不同按钮的次数。 每次用户点击按钮,你就在一个记录本上对应的按钮旁边记下一笔,最后你就可以知道每个按钮被点击了多少次。 function Counting(arr) { return arr.reduce((total, currentValue) => { total[currentValue] = (total[currentValue] || 0) + 1; return total; }, {}); } const userActions = ['click', 'scroll', 'click', 'hover', 'click']; console.log(Counting(userActions)); // 输出:{ 'click': 3, 'scroll': 1, 'hover': 1 } reduce:就像在帮你统计每个事件的发生次数。 total[currentValue]:这是记录本上对应事件的计数。 total[currentValue] || 0:如果这个事件还没被记录过,就初始化为0。 +1:每次事件发生,就在对应的计数上加1。

     4. 查找元素位置

    想象你在一堆订单中寻找那些出了问题的订单(比如状态为“异常”),就像在一份名单中标记出所有异常订单的位置,以便后续处理。 function Position(arr, val) { return arr.reduce((total, currentValue, currentIndex) => { if (currentValue.status === val) { total.push(currentIndex); } return total; }, []); } const orders = [ { id: 1, status: 'completed' }, { id: 2, status: 'pending' }, { id: 3, status: 'exception' }, { id: 4, status: 'exception' } ]; console.log(Position(orders, 'exception')); // 输出:[2, 3] reduce:就像在浏览订单列表,每找到一个符合条件的订单,就记下它的位置。 currentValue.status === val:检查当前订单是否是“异常”状态。 push(currentIndex):如果是异常订单,就把它的位置(索引)记录下来。

     5. 组合函数——订单折扣计算

    想象你在为用户计算订单总价,这个过程就像在制作一道美味的菜肴,需要按顺序添加各种配料(折扣、会员优惠、税费)。 每一步都对最终的味道(价格)有影响,最后得到的是用户需要支付的总价。 const addDiscount = (x) => x - 5; const applyMemberDiscount = (x) => x * 0.9; const addTax = (x) => x + (x * 0.08); const composedFunctions = [addDiscount, applyMemberDiscount, addTax]; const finalPrice = composedFunctions.reduce((total, currentValue) => currentValue(total), 100); console.log(finalPrice); composedFunctions:这里的数组就像一系列步骤,每一步都对订单总价进行处理。 reduce:依次执行每个步骤,把当前的价格传给下一个处理函数。 100:初始的订单价格。 finalPrice:经过所有处理后的最终订单价格。

     6. 数组去重——数据清洗中的重复项去除

    想象你在整理一堆文件(数据),不小心有些文件重复了。 为了确保每个文件只保留一份,你需要把重复的文件清理掉。 reduce方法就像一个过滤器,帮你把这些重复项去掉,只留下唯一的文件。 function Uniq(arr) { return arr.reduce((total, currentValue) => total.includes(currentValue) ? total : [...total, currentValue], []); } const rawData = [2, 1, 0, 3, 2, 1, 2]; console.log(Uniq(rawData)); // 输出:[2, 1, 0, 3] reduce:就像一个过滤器,遍历数组中的每个元素。 total.includes(currentValue):检查当前元素是否已经存在于结果数组中。 total:如果当前元素已经存在,就跳过;否则,把它加到结果数组中。

     7. 计算平均值——用户评分系统

    想象你在收集用户对某个产品的评分,现在你需要计算出这个产品的平均评分,就像把所有评分加起来,然后平分给每个用户,得到一个平均分。 reduce方法可以帮你快速完成这个计算。 function Average(arr) { return arr.reduce((total, currentValue, currentIndex, array) => { total += currentValue; if (currentIndex === array.length - 1) { return total / array.length; } return total; }, 0); } const ratings = [4, 5, 3, 4, 5]; console.log(Average(ratings)); // 输出:4.2 reduce:就像一个评分收集器,遍历每个用户的评分。 total += currentValue:把每个评分累加到总分里。 if (currentIndex === array.length - 1):在最后一个评分加完后,计算平均值。 total / array.length:总分除以评分人数,得到平均分。 • reduce:就像一个评分收集器,遍历每个用户的评分。 total += currentValue:把每个评分累加到总分里。 if (currentIndex === array.length - 1):在最后一个评分加完后,计算平均值。 total / array.length:总分除以评分人数,得到平均分。

     8. 找最大值和最小值——商品价格筛选

    想象你在逛一个电商平台,正在寻找一件最便宜或者最贵的商品。 你可能会逐个查看商品的价格,然后记住当前看到的最低价或最高价。 reduce方法就像你的记忆助手,帮你快速找出列表中最高或最低的价格。 function Max(arr = []) { return arr.reduce((total, currentValue) => total > currentValue ? total : currentValue); } function Min(arr = []) { return arr.reduce((total, currentValue) => total < currentValue ? total : currentValue); } const prices = [120, 450, 210, 650, 380]; console.log(Max(prices)); // 输出:650 console.log(Min(prices)); // 输出:120 Max函数:通过遍历数组,记住当前看到的最大价格。 Min函数:同样遍历数组,记住当前看到的最小价格。 reduce:在遍历过程中比较每个商品的价格,并更新最大值或最小值。

     9. URL 参数解析——处理用户请求中的查询参数

    想象你在开发一个搜索功能,当用户在搜索框中输入条件并提交时,URL会包含这些查询参数。 你需要把这些参数拆解开,放到一个对象里,这样你就可以用它们来执行搜索查询。 reduce方法可以帮你轻松完成这一步。 function ParseUrlSearch(str) { return str.replace(/(^\?)|(&$)/g, "").split("&").reduce((total, currentValue) => { const [key, val] = currentValue.split("="); total[key] = decodeURIComponent(val); return total; }, {}); } const url = 'key1=value1&key2=value2&key3=value3'; console.log(ParseUrlSearch(url)); // 输出:{ key1: 'value1', key2: 'value2', key3: 'value3' } replace(/(^?)|(&$)/g, ""):去掉URL中的问号或其他特殊符号,留下纯参数部分。 split("&"):将参数字符串按“&”分隔成一个数组,每个元素是一个“key=value”的形式。 reduce:遍历这个数组,把每个“key=value”解析成键值对,存入一个对象中。 decodeURIComponent(val):对参数值进行解码,以防止URL编码问题。

     10. URL 参数序列化——生成API请求参数

    想象你在准备向后端发送一个API请求,你手里有一张列着参数的清单(对象),但后端要求你把这些参数按一定格式(查询字符串)打包发送。 reduce方法就像一个打包工具,把这些参数按照规定的格式整理好,方便你发送请求。 function StringifyUrlSearch(search) { return Object.entries(search).reduce( (total, currentValue) => `${total}${currentValue[0]}=${encodeURIComponent(currentValue[1])}&`, Object.keys(search).length ? "?" : "" ).replace(/&$/, ""); } const params = { foo: "bar", baz: 42 }; console.log(StringifyUrlSearch(params)); // 输出:"?foo=bar&baz=42" Object.entries(search):将对象转换为一个二维数组,每个元素是一个[key, value]对,方便遍历。 reduce:遍历每个参数对,将它们拼接成“key=value”的形式,并用“&”连接。 encodeURIComponent(currentValue[1]):对参数值进行编码,确保特殊字符在URL中合法。 replace(/&$/, ""):去掉最后一个多余的“&”符号,使查询字符串格式正确。

     11. 对象分组——按属性分组用户数据

    想象你在管理一个大型的用户数据库,你需要根据用户的某个属性(比如年龄)将他们分组,这样可以更方便地进行统计和分析。 reduce方法就像一个分类器,帮你把用户按照指定的属性归类到不同的组里。 function Grouping(arr, key) { return arr.reduce((total, currentValue) => { if (!total[currentValue[key]]) { total[currentValue[key]] = []; } total[currentValue[key]].push(currentValue); return total; }, {}); } const users = [ { name: 'Alice', age: 25 }, { name: 'Bob', age: 30 }, { name: 'Charlie', age: 25 }, { name: 'Dave', age: 30 } ]; console.log(Grouping(users, 'age')); /* 输出: { '25': [{ name: 'Alice', age: 25 }, { name: 'Charlie', age: 25 }], '30': [{ name: 'Bob', age: 30 }, { name: 'Dave', age: 30 }] } */ reduce:就像在整理用户数据,根据指定的属性(比如年龄)将用户归类。 total[currentValue[key]]:检查当前分类组是否已经存在,如果不存在,就创建一个新的数组来存放这一组用户。 push(currentValue):将用户添加到对应的分组中。

     12. 创建查找表——快速查找产品信息

    想象你在管理一个电商平台,需要快速找到某个产品的详细信息。 如果有一个查找表(类似目录),你只需根据产品ID就能快速找到对应的产品信息。 reduce方法可以帮你把产品数组转换为这样的查找表。 function arrayToMap(arr, key) { return arr.reduce((total, currentValue) => { total[currentValue[key]] = currentValue; return total; }, {}); } const products = [ { id: 1, name: 'Laptop', price: 999 }, { id: 2, name: 'Phone', price: 699 }, { id: 3, name: 'Tablet', price: 499 }, ]; const productMap = arrayToMap(products, 'id'); console.log(productMap); /* 输出: { '1': { id: 1, name: 'Laptop', price: 999 }, '2': { id: 2, name: 'Phone', price: 699 }, '3': { id: 3, name: 'Tablet', price: 499 } } */ reduce:遍历产品数组,逐一处理每个产品。 total[currentValue[key]] = currentValue:将产品的ID作为查找表的键,产品的详细信息作为对应的值,存入查找表。 total:最终形成一个以产品ID为键,产品信息为值的对象,方便快速查找。

     13. 合并数组为对象——将表单字段与值配对

    想象你在处理一份表单,表单上有多个字段(比如姓名、年龄、性别),用户填写了相应的值。 现在你需要把这些字段名和用户输入的值配对,形成一个对象,以便提交给后端处理。 reduce方法可以帮你将这两个数组合并成一个对象。 function Merge(arr1, arr2) { return arr1.reduce((total, currentValue, index) => { total[currentValue] = arr2[index]; return total; }, {}); } const fields = ['name', 'age', 'gender']; const values = ['Alice', 25, 'female']; console.log(Merge(fields, values)); // 输出:{ name: 'Alice', age: 25, gender: 'female' } reduce:遍历字段数组arr1,逐一处理每个字段。 total[currentValue] = arr2[index]:将字段名作为对象的键,将对应的用户输入值作为值,添加到对象中。 index:通过索引匹配字段名和对应的输入值。

     14. 检查字符串是否为回文——验证用户输入

    想象你在开发一个系统,需要验证用户输入的字符串是否是回文。 回文指的是正着读和倒着读都一样的字符串,比如“racecar”。 reduce方法可以帮你快速检查这个字符串是否符合回文的要求。 function isPalindrome(str) { return str.split('').reduce((total, currentValue, index, array) => { return total && currentValue === array[array.length - index - 1]; }, true); } const input = 'racecar'; console.log(isPalindrome(input)); // 输出:true split(''):将字符串分割成单个字符的数组。 reduce:遍历字符数组,逐个比较字符是否对称。 total && currentValue === array[array.length - index - 1]:检查当前字符是否与对应位置的字符相同,如果全部匹配,则为回文。

    箭头函数与arguments对象

    代码分析

    const func = () => arguments.length; console.log(func(1, 2, 3)); 箭头函数与 arguments 对象: 在JavaScript中,arguments 对象是一个类数组对象,它包含了传递给函数的所有参数。 传统的函数表达式和函数声明中可以访问 arguments 对象。 然而,箭头函数没有自己的 arguments 对象。 它会从其外层作用域中继承 arguments。 为什么会出错: 当你调用 func(1, 2, 3) 时,JavaScript 会尝试在箭头函数内部访问 arguments。 由于箭头函数没有自己的 arguments 对象,JavaScript 会向外查找,但外层作用域中也没有 arguments 的定义。 这种情况下,JavaScript 会抛出一个 ReferenceError,说明 arguments 未定义。 不论是在严格模式还是非严格模式下,这段代码都会抛出相同的错误,因为 arguments 变量在箭头函数的上下文中是不可用的。 所以选择 B:Error

    解决方法

    如果你想在函数中获取传递的参数数量,可以使用 rest 参数代替 arguments,或者改用普通函数表达式。

     使用 rest 参数:

    const func = (...args) => args.length; console.log(func(1, 2, 3)); // 输出 3

     使用普通函数表达式:

    function func() { return arguments.length; } console.log(func(1, 2, 3)); // 输出 3

    结束

    箭头函数没有自己的 arguments 对象,这一点在使用时需要特别注意。 理解这一点对准确编写和调试JavaScript代码非常重要。

    纯前端实现语音文字互转

    Web Speech API 的引入使得开发者能够在浏览器中轻松实现语音识别和语音合成功能,为用户带来更加直观和便捷的操作体验。

    什么是 Web Speech API?

    Web Speech API 是一组浏览器 API,允许开发者在 Web 应用程序中集成语音识别和语音合成功能。 这些 API 的引入标志着浏览器开始支持本地端的语音交互能力,不仅改善了用户体验,还为开发者提供了更多创新的可能性。

    主要组成部分

    Web Speech API 包括两个核心部分: SpeechRecognition(语音识别) : 允许用户通过麦克风输入语音,然后将其转换为文本。 可以检测语音的开始和结束,以便进行适当的处理和响应。 提供了各种配置选项,如语言识别设置、连续识别等,以满足不同应用场景的需求。 SpeechSynthesis(语音合成) : 允许开发者将文本转换为语音输出。 支持多种语音合成引擎和语音效果,可以根据需求选择合适的语音风格和语言。 提供了控制音调、语速等参数的接口,以实现个性化的语音输出效果。

    优势

    多语言支持: Web Speech API 支持多种语言,可0以通过设置 recognition.lang 或 utterance.lang 来切换不同的语言环境。 例如,识别法语、西班牙语等。 语音指令的识别: 不仅仅是简单的文本转换,可以实现对特定命令或短语的识别,如控制网页的导航、播放媒体等。 这需要在识别的事件处理程序中进行语音指令的解析和响应。 连续语音识别: 设置 recognition.continuous = true,使得语音识别能够持续监听用户的语音输入,而不是单次识别。 实时反馈和动态调整: 根据识别的实时结果,可以实现实时反馈或动态调整应用程序的行为。 例如,在用户说话时动态更新界面或提供即时建议。

    如何使用 Web Speech API?

     实现语音识别

    属性
    recognition.grammars 用于存储一组语法规则,可以通过 addFromString 方法添加语法规则。 recognition.lang 设置或获取语音识别的语言 recognition.interimResults 如果设置为 true,则在识别过程中会提供临时结果。 如果为 false,则只提供最终结果 recognition.maxAlternatives 设置语音识别返回的替代结果的最大数量。 默认值为 1,表示只返回最可能的结果 recognition.continuous 如果设置为 true,则识别会持续运行直到显式停止。 如果为 false,识别会在单次语音输入后自动停止 recognition.onresult 当识别结果可用时触发的事件处理程序。 事件对象的 results 属性包含识别结果 recognition.onaudiostart 当开始录制音频时触发的事件处理程序 recognition.onsoundstart 当检测到声音时触发的事件处理程序 recognition.onspeechstart 当检测到用户开始说话时触发的事件处理程序 recognition.onspeechend 当用户停止说话时触发的事件处理程序 recognition.onaudioend 当音频录制停止时触发的事件处理程序 recognition.onend 当语音识别结束时触发的事件处理程序 recognition.onerror 当语音识别发生错误时触发的事件处理程序。 事件对象的 error 属性包含错误信息 recognition.onnomatch 当语音识别没有匹配到任何结果时触发的事件处理程序 recognition.onsoundend 当检测到的声音停止时触发的事件处理程序
    事件
    start() 启动语音识别 stop() 停止语音识别 abort() 终止语音识别,并且不会触发onend事件 通过以下简单的 JavaScript 代码片段,可以实现基本的语音识别功能: const recognition = new webkitSpeechRecognition(); // 创建语音识别对象 recognition.lang = 'en-US'; // 设置识别语言为英语 recognition.onresult = function(event) { const transcript = event.results[0][0].transcript; // 获取识别结果文本 console.log('识别结果:', transcript); }; recognition.start(); // 开始识别

     实现语音合成

    属性
    SpeechSynthesisUtterance.lang 获取并设置说话的语言 SpeechSynthesisUtterance.pitch 获取并设置说话的音调(值越大越尖锐,越小越低沉) SpeechSynthesisUtterance.rate 获取并设置说话的速度(值越大越快) SpeechSynthesisUtterance.text 获取并设置说话的文本 SpeechSynthesisUtterance.voice 获取并设置说话时的声音 SpeechSynthesisUtterance.volume 获取并设置说话的音量
    事件
    speak() 将对应的实例添加到语音队列中 cancel() 删除队列中所有的语音,如果正在播放,则直接停止 pause() 暂停语音 resume() 恢复暂停的语音 getVoices 获取支持的语言数组 使用 SpeechSynthesis API 实现文本转语音的功能,示例代码如下: const utterance = new SpeechSynthesisUtterance('Hello, welcome to our website.'); utterance.lang = 'en-US'; // 设置语音合成的语言 window.speechSynthesis.speak(utterance); // 开始语音合成

    SpeechGrammar

    1. 什么是 SpeechGrammar?

    SpeechGrammar 对象用于指定一个语法规则,这些规则可以帮助语音识别引擎识别特定的语音输入。 它常与 SpeechRecognition 对象结合使用。 语法规则可以是简单的文本,也可以是复杂的正则表达式或者语法定义。

    2. 如何使用 SpeechGrammar?

    要使用 SpeechGrammar,你需要创建一个 SpeechRecognition 对象,并为其添加一个或多个 SpeechGrammar 对象。 以下是一个示例: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Speech Grammar Example</title> </head> <body> <button id="startButton">Start Speech Recognition</button> <div id="output"></div> <script> // 确保浏览器支持 SpeechRecognition const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; if (!SpeechRecognition) { console.error("SpeechRecognition not supported"); } else { // 创建 SpeechRecognition 实例 const recognition = new SpeechRecognition(); // 定义语法规则 const grammar = '#JSGF V1.0; grammar colors; public <color> = red | green | blue | yellow ;'; // 创建 webkitSpeechGrammarList 实例 const speechGrammarList = new webkitSpeechGrammarList(); speechGrammarList.addFromString(grammar, 1); // 1 是语法的优先级 // 将语法列表应用到 SpeechRecognition 实例 recognition.grammars = speechGrammarList; // 配置识别选项 recognition.lang = 'en-US'; // 设置语言 recognition.interimResults = false; // 只返回最终结果 recognition.maxAlternatives = 1; // 只返回一个替代结果 // 开始识别 recognition.start(); recognition.onresult = (event) => { const result = event.results[0][0].transcript; console.log('识别结果:', result); }; recognition.onerror = (event) => { console.error('识别错误:', event.error); }; } </script> </body> </html> 通过合理使用 SpeechGrammar 和 SpeechRecognition,你可以创建更精确的语音识别应用,提升用户体验。

    实际应用场景包括但不限于:

    智能助手和语音搜索: 实现类似于 Siri、Google Assistant 等智能助手的语音控制和信息获取功能。 无障碍和辅助技术: 支持视觉障碍用户的语音导航、文本转语音等辅助功能。 教育和培训: 提供基于语音的学习和培训工具,如语音答题、学习笔记转录等。 娱乐和游戏: 实现语音驱动的游戏操作和交互体验,如语音控制角色移动、发声识别等。

    开源数学公式渲染库 KaTeX

    1、KaTeX 是什么?

    KaTeX 是一个集成速度快且功能丰富的数学公式渲染库,专为 Web 设计。 它由 Khan Academy 开发,提供接近印刷品质的数学公式展示,同时保持与浏览器的高效互动性。 KaTeX 特点包括快速渲染速度、高质量的输出、独立运行、跨平台兼容以及丰富的功能集。 它支持服务器端渲染,可以预渲染公式并作为纯 HTML 发送,减轻客户端负担。

    2、快速开始

    安装及引入 KaTex 支持包管理器 npm、yarn 和 CDN 方式安装,根据需要选择安装方式。 # npm npm i katex # yarn yarn add katex 如果在 React 中使用,可以考虑安装 react-katex 包,提供一个 React 组件简化数学公式的渲染过程。 npm i react-katex katex # 还有 vue 版本的 npm i vue-katex katex KaTex 还有很多扩展库,具体可以参考这个地址[3]。 入门示例 作为入门演示示例,下载源码到本地方式引入 KaTex。 <!-- 引入样式和库文件 --> <link rel="stylesheet" href="../libs/katex.css" /> <script src="../libs/katex.js"></script> 创建容器 DOM 元素,绑定 equation ID 选择器 <div id="equation">$`x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}`$</div> <script type="text/javascript" defer> // 使用KaTeX渲染指定元素中的公式 katex.render(`x=\frac{-b\pm\sqrt{b^2-4ac}}{2a}`, document.getElementById('equation')) </script> 效果

    3、核心功能及 API

    KaTeX 核心功能包括同步渲染机制、基于 TeX 的布局算法、自定义的样式和布局选项。 它的 API 允许开发者通过 JavaScript 控制渲染过程,包括手动渲染特定元素或批量渲染文档中的所有公式。 自动渲染 使用 JavaScript 手动渲染还是稍微麻烦了一点,官方提供 auto-render 自动渲染扩展,通过简单的引入可以实现自动渲染。 // 引入 auto-render.js <script src="../libs/auto-render.js"></script> <script type="text/javascript" defer> document.addEventListener('DOMContentLoaded', function() { renderMathInElement(document.body, { // 自定义选项 // • auto-render 指定解析格式 delimiters: [ { left: '$$', right: '$$', display: true }, { left: '$', right: '$', display: false }, { left: '\\(', right: '\\)', display: false }, { left: '\\[', right: '\\]', display: true }, ], // • 不抛出异样,而是渲染公式源码 throwOnError: false, }) }) </script> auto-render 扩展可以在页面加载时自动查找并渲染所有使用 $...$ 和 $$...$$ 包裹的公式。 意味着你不需要手动调用任何函数来渲染这些公式。 KaTeX 允许调整样式,例如修改 .katex 类的 font-size 属性来改变公式的显示大小。 此外,KaTeX 提供了多个扩展,如 copy-tex 扩展允许复制 LaTeX 代码,而 mhchem 扩展简化了化学方程式的编写。

    4、应用场景

    KaTeX 适用于多种场景,包括在线教育平台、科学期刊网站、个人博客、数学问题社区以及印刷出版。 它能够将 LaTeX 代码转换为可读性强、易于复制粘贴的格式,有助于读者理解复杂的数学表达式。 KaTeX 的优势在于它的渲染速度快于其他数学公式渲染库,同时保持高质量的输出,这使得它适用于对性能要求较高的实时互动环境。

    5、同类对比

    与 MathJax 相比 KaTeX 提供更快的渲染速度,更适合需要即时响应的应用。 KaTeX 的设计注重于减少页面重排,提供更流畅的用户体验。 MathJax 提供更多的 LaTeX 功能和包支持。 根据需要,注重简洁性和高性能选择 KaTex,注重功能和包支持,选择 MathJax。

    image manipulation

    Sharp.js Cropper.js Merge Images.js LooksSame.js Jimp.js https://sharp.pixelplumbing.com/api-resize#extract

    browser tesseract

    <script src='https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js'></script> <script> (async () => { const worker = await createWorker('eng'); const ret = await worker.recognize('https://tesseract.projectnaptha.com/img/eng_bw.png'); console.log(ret.data.text); await worker.terminate(); })(); (async () => { const worker = await Tesseract.createWorker('chi_sim'); // chi_tra, eng //const ret = await worker.recognize('https://tesseract.projectnaptha.com/img/eng_bw.png'); const ret = await worker.recognize('https://media.istockphoto.com/id/1701859331/zh/%E5%90%91%E9%87%8F/set-of-numbers-written-by-brush.jpg?s=1024x1024&w=is&k=20&c=s_Khcm5ovYBy3APVOO9kfpZp6cYdF2pX5iU15KCCxuM='); console.log(ret.data.text); await worker.terminate(); })(); // A worker is created once and used every time a user uploads a new file. </script> When recognizing multiple images, users should create a worker once, run worker.recognize for each image, and then run worker.terminate() once at the end (rather than running the above snippet for every image).

    web实现drag拖拽布局

    这种拖拽布局功能其实在电脑操作系统或者桌面应用里面是经常使用的基础功能,只是有时候在进行web开发的时候,对这个功能需求量不够明显,但却是很好用,也很实用。 静态效果: 动态效果: 为了查看更佳效果,需要把源码在浏览器上运行起来。 另一个值得关心的事项:案例中左右盒子是可以完全拖拽关闭的,也就是宽度为0px。 实际应用中可能不需要这种效果,没关系,可以限制左右盒子的最小宽度,判断小于最小宽度就不再进行缩小即可,放大限制 也是类似的。 实现原理 想象一下,拖拽布局一般都需要两个div盒子,同时需要一个可以拖拽的class=resize盒子(以下简称resize),它们都是块元素。 然后加上HTML标签和css的基础左右布局样式,大致轮廓就出来了。 到这里还没有实现拖拽resize布局逻辑,接着往下看。 拖拽resize原理分析: 当用户把鼠标移动到resize盒子上面,此时出现可以左右拖拽的标识,这个标识可以用css的cursor: w-resize来实现。 如果用户按下鼠标左键,可以监听鼠标按下事件,获得鼠标按下的startX = evt.clientX,也能获得resize相对于父元素的左偏移值offsetLeft。 resizeBar.onmousedown(evt) { var startX = e.clientX; resizeBar.left = resizeBar.offsetLeft; } 如果用户按住鼠标左键开始向左或者向右拖拽,需要精确计算用户拖拽的实际距离,也是鼠标移动的实际距离。 计算方式:resize的左偏移值offsetLeft+(鼠标移动实际距离 + 鼠标按下距离)= 实际移动距离movelen。 document.onmousemove = function(e) { var moveLen = resizeBar.left + (e.clientX - startX); } 那么,resize的左边距离移动实际距离就是这样获得的。 document.onmousemove = function(e) { var moveLen = resizeBar.left + (e.clientX - startX); resizeBar.style.left = moveLen + 'px'; } 左边|右边盒子宽度就可以得到了。 document.onmousemove = function(e) { var moveLen = resizeBar.left + (e.clientX - startX); resizeBar.style.left = moveLen + 'px'; leftBox.style.width = moveLen + "px"; rightBox.style.width = boxWidth - resizeWidth - moveLen + "px"; } 到这里拖拽核心逻辑就结束了,为了更好的理解拖拽过程,于是就有了下方不怎么好看的抽象图,画的不好,多多理解。 源码贴上 HTML <body> <div> <div> <p>左边盒子</p> </div> <div></div> <div> <p>右边盒子</p> </div> </div> </body> CSS <style> .box { width: 100%; height: 100vh; display: flex; } .left { background: lightblue; } .resize { width: 10px; height: 100%; background-color: #399aef; cursor: w-resize; } .right { background: rgba(0, 0, 0, 0.4); } p { padding: 20px; text-align: center; font-size: 25px; font-weight: 600; } [class*="overflow"] { width: 49%; height: 100%; overflow: hidden; } .userselect { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } </style> JavaScript <script> function dragResize() { var resizeBar = document.querySelector(".resize"); var leftBox = document.querySelector(".left"); var box = document.querySelector(".box"); var rightBox = document.querySelector(".right"); var resizeWidth = resizeBar.offsetWidth; var boxWidth = box.offsetWidth; resizeBar.onmousedown = function(e) { var startX = e.clientX; resizeBar.left = resizeBar.offsetLeft; // 鼠标拖动事件 document.onmousemove = function(e) { var moveLen = resizeBar.left + (e.clientX - startX); resizeBar.style.left = moveLen + 'px'; leftBox.style.width = moveLen + "px"; rightBox.style.width = boxWidth - resizeWidth - moveLen + "px"; e.target.style.cursor = "w-resize" // 拖拽过程中,禁止选中文本 leftBox.classList.add('userselect') rightBox.classList.add('userselect') }; // 鼠标松开事件 document.onmouseup = function(evt) { document.onmousemove = null; document.onmouseup = null; // 清空cursor leftBox.style.cursor = "default" rightBox.style.cursor = "default" leftBox.classList.remove('userselect') rightBox.classList.remove('userselect') }; }; } dragResize()

    的 Rest 和 Spread 操作符

    Rest 和 Spread 操作符简介

    Rest 操作符(...)允许你将多个元素收集到一个数组或对象中,通常用于函数参数中,将参数列表转换为数组。 而 Spread 操作符(...)则用于将数组或对象展开为单个元素,这在复制、合并或传递数组和对象时特别有用。 理解并掌握这些操作符可以大大提升你的 JavaScript 编码水平,使代码更加简洁和富有表现力。

    Rest 操作符的应用

    函数参数处理 Rest 操作符在函数定义中非常有用,可以处理不定数量的参数: function multiply(...numbers) { return numbers.reduce((product, number) => product * number, 1); } console.log(multiply(2, 3, 4)); // 输出: 24 在这个例子中,multiply 函数接受任意数量的参数并进行相乘。 Rest 操作符将所有参数收集到 numbers 数组中,使得可以轻松应用 reduce 等数组方法。 数组解构 Rest 操作符还可以在数组解构中使用,将剩余元素收集到一个新数组中: const [head, ...tail] = ['a', 'b', 'c', 'd']; console.log(head); // 输出: 'a' console.log(tail); // 输出: ['b', 'c', 'd'] 在这个例子中,数组的第一个元素被赋值给 head,其余元素则被收集到 tail 数组中。

    Spread 操作符的应用

    数组合并 使用 Spread 操作符,数组合并变得非常简单: const fruits = ['apple', 'banana']; const vegetables = ['carrot', 'potato']; const food = [...fruits, ...vegetables]; console.log(food); // 输出: ['apple', 'banana', 'carrot', 'potato'] 在这个例子中,Spread 操作符将 fruitsvegetables 展开为单个元素并合并到 food 数组中。 数组复制 创建数组副本同样很方便: const numbers = [1, 2, 3]; const numbersCopy = [...numbers]; console.log(numbersCopy); // 输出: [1, 2, 3] 这样创建了一个包含与 numbers 数组相同元素的新数组 numbersCopy,修改 numbersCopy 不会影响 numbers对象合并 Spread 操作符还可以用于对象的合并: const person = { name: 'Alice', age: 25 }; const job = { title: 'developer', company: 'Tech Co.' }; const employee = { ...person, ...job }; console.log(employee); // 输出: { name: 'Alice', age: 25, title: 'developer', company: 'Tech Co.' } 在这个例子中,personjob 被合并到 employee 对象中,形成一个新的对象。

    高级技巧

    对象解构中的 Rest 操作符 Rest 操作符可以在对象解构中使用,收集剩余的属性: const { title, ...details } = { title: 'Book', author: 'John Doe', year: 2021 }; console.log(title); // 输出: 'Book' console.log(details); // 输出: { author: 'John Doe', year: 2021 } 这个例子展示了如何提取特定属性(title),同时将剩余属性收集到 details 对象中。 Spread 操作符用于函数参数 在调用接受多个参数的函数时,Spread 操作符可以简化传递数组元素作为参数: function concatenate(str1, str2, str3) { return str1 + str2 + str3; } const words = ['Hello', ' ', 'World!']; console.log(concatenate(...words)); // 输出: 'Hello World!' 通过展开 words 数组,每个元素作为独立参数传递给 concatenate 函数。

    Plyr.js HTML5 播放器

    <script src="https://cdn.plyr.io/3.7.8/plyr.js"></script> <video id="player" playsinline controls> <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4" type="video/mp4" /> </video> 具有响应式设计,适用于任何屏幕尺寸,并支持多种功能,如字幕控制、分辨率控制、播放速度控制、画中画模式播放、API 切换播放、音量、搜索等 。 还支持多种字幕轨道、预览缩略图、键盘快捷键、全屏播放以及国际化支持。

    自定义音量控制

    lt;input id="volume-control" type="range" min="0" max="1" step="0.05" value="1"> 设置事件监听器 为自定义的音量控制添加事件监听器,当用户改变音量控制时,使用 Plyr 的 API 来设置播放器的音量。 document.getElementById('volume-control').addEventListener('input', function() { player.volume = this.value; }); 获取当前音量并设置初始值 如果你想要在页面加载时设置自定义音量控制的初始值,你可以从 Plyr 播放器获取当前音量并设置它。 const volumeControl = document.getElementById('volume-control'); volumeControl.value = player.volume; // 设置初始音量 响应音量变化 确保当 Plyr 播放器的音量发生变化时,自定义的音量控制也能相应地更新。这可以通过监听 Plyr 播放器的 volumechange 事件来实现。 player.on('volumechange', function(event) { volumeControl.value = event.detail.value; });

    使用JavaScript读取手机联系人列表



    Read Phone Contacts with JavaScript https://stackoverflow.com/questions/60339201/can-i-get-a-phone-contacts-list-with-javascript 作者注:本文中描述的技术和流程是实验性的,只能在少数浏览器中工作。 在撰写本文时,联系人选择器API仅支持 Android Chrome(从版本80开始)和iOS Safari(从版本14.5开始)。 在以前使用JavaScript从手机访问联系人数据是不可想象的。 现在有了联系人选择器API,我们可以使用JavaScript来实现这个功能。 此功能在需要联系人信息(如电话号码或VoIP)的应用程序,通过这个功能我们可以在社交平台中发现通讯录中的好友(前提需要社交平台有对应的手机号码字段),或者需要填写联系人表单信息时则无需切换应用程序即可获取到相应的数据。

    API和设备将限制可用的属性

    开发者可以选择以下五个标准属性: 姓名 电话 电子邮件 地址 图标 以上返回的都是数组形式,因为联系人可以有多个电话、电子邮件或多个地址。 为了保持一致性,即使它是单个值,返回的数据始终是一个数组。

    隐私和安全

    存储在手机上的联系人信息可能包含敏感信息,我们必须小心处理。 我们需要必须考虑到隐私和安全问题: 联系人选择器API代码必须在顶级浏览上下文中运行。它防止外部代码,如广告或第三方插件,读取手机上的联系人列表。 联系人选择器API代码只能在用户手势后运行。开发者不能完全自动化这个过程,用户必须采取行为触发后读取联系人。 用户必须允许访问联系人列表。这个是由手机限制而不是JavaScript强加的。 用户必须授予浏览器访问联系人的权限(如果它还没有授权)。 当他们第一次使用使用联系人选择器API的网站时,他们可能会收到提示 手机会在每次使用联系人选择器API代码时显示这个弹出窗口,直到用户点击“允许”。 联系人选择器API在未允许之前不会运行。 这个一次性的,授权之后不会再弹出。

    API和代码

    联系人选择器API只定义了两个方法: getProperties():返回设备上可读取的属性列表。 在定义中有五个值:"address"(地址)、"email"(电子邮件)、"icon"(这可能不是联系人图片)、"name"(姓名)、"tel"(电话),但设备可能不允许访问所有这些属性。 select():打开联系人弹出窗口,并在用户完成操作后返回选择。 它接受两个参数:要读取的属性列表和一个可选的对象,包含选项。 两种方法都返回Promise,但考虑到它们触发的操作会阻止应用程序的正常流程,我们在处理它们时应该使用async / await。 如前面隐私和安全部分所述,在调用API之前需要用户操作,因此如果没有用户交互,我们就无法触发任何内容,因此我们新增一个按钮: <button onclick="getContactData()">Show contact data</button> 主要的代码将在getContactData()函数中。 但在此之前如果联系人选择器API不可用,显示按钮没有意义,在默认情况下隐藏按钮(添加hidden属性),仅在API可用时才显示它。 通过 "contacts" in navigator判断当前浏览器环境是否支持该API: if ("contacts" in navigator) { document.querySelector("button").removeAttribute("hidden"); } 接下来是核心的按钮逻辑: async function getContactData() { // 指定将读取哪些联系人值 const props = ["tel", "name", "email"]; try { // 打开本地联系人选择器(在权限被授予后) const contacts = await navigator.contacts.select(props); // 这将在本地联系人选择器关闭后执行 if (contacts.length) { // 如果有数据,显示 alert("选中的数据: " + JSON.stringify(contacts)); } else { // 没有表示没有选择 alert("没有选择任何内容"); } } catch (ex) { // 如果发生错误,显示错误信息 alert(ex.message) } } 一旦按钮触发了这个功能,如果浏览器有权限,联系人选择页将会显示出来,展示基本信息:阅读数据的URL,它将返回什么数据,以及要从中挑选的联系人列表。 关闭弹窗后,contacts变量将以JSON格式存储数据,作为一个数组,其中包含所请求信息的对象(如果联系人卡片中不可用,则可能为空)。 这是选择了联系人后的结果示例: [ { "address": [], "email": [ "alvarosemail@gmail.com" ], "icon": [], "name": [ "Alvaro Montoro" ], "tel": [ "555-555-5555", "555-123-4567" ] } ] 如果数据包含图标,则它将是带有图像的blob。 如果数据包含地址,它将是一个更复杂的对象,包含街道、城市、国家、邮政编码等。

    选择多个联系人

    可以选择多个联系人。 我们需要向navigator.contacts.select()方法传递第二个参数来指示此选项。 const props = ["tel", "address", "icon", "name", "email"]; const options = { multiple: true }; const contacts = await navigator.contacts.select(props, options); 结果是一个联系人数组,和上面的示例返回结果是一样的。

    总结

    联系信息是个人身份信息,我们必须以敏感数据所需的所有谨慎和安全性来处理它。 尊重人们的隐私。 不要强迫他们分享他们不想分享的信息。 以安全的方式小心处理数据。 如果您正在处理的数据是您自己的数据,您会感到舒适吗? 如果不需要,请不要存储数据。 读它,用它,忘记它。 不要存储你不使用的数据。 只获取您需要的数据。 获得建立信誉和信任所需的一切。 假设一个Web应用程序试图在选择电话号码时读取地址、姓名或电子邮件。 如果这种情况发生在我身上,我会拒绝授权并离开这个网站。

    前端实现gzip打包压缩



    1.1.什么是GZIP压缩

    GZIP是一种广泛使用的文件压缩格式,它使用LZ77算法进行数据压缩,并通常用于减少文件大小,以便更快地在网络上传输。 GZIP不仅被用来压缩单个文件,还可以用来压缩整个目录结构。 在Web开发中,GZIP压缩特别有用,因为它可以显著减少HTTP响应的大小,从而加快网页加载速度。

    1.2.前端实现GZIP打包压缩

    在前端开发中,GZIP压缩通常不是直接由前端代码执行的,而是通过构建工具或者服务器配置来完成。 不过,如果你想要在前端环境中生成GZIP压缩的文件,可以通过以下几种方式实现:

    1.2.1.使用Node.js和构建工具

    Webpack const CompressionWebpackPlugin = require('compression-webpack-plugin'); module.exports = { // ... plugins: [ new CompressionWebpackPlugin({ algorithm: 'gzip', test: /\.js$|\.css$|\.html$/, threshold: 10240, minRatio: 0.8 }) ], // ...}; 安装Webpack插件 compression-webpack-plugin。 在Webpack配置文件中启用这个插件。 Rollup 安装 rollup-plugin-gzip 或者类似的插件。 在Rollup配置文件中添加该插件。 Parcel Parcel 自动支持 GZIP 压缩,无需额外配置。 其他构建工具 如Gulp或Grunt也有相应的插件支持GZIP压缩。

    1.2.2.使用JavaScript API

    如果需要在浏览器端进行压缩(虽然这并不常见),可以使用一些JavaScript库如 pako 或 lz-string。 例如使用 pako 库进行GZIP压缩: 安装pako npm install pako 压缩文件 import pako from 'pako'; function compressToGzip(data) { const compressed = pako.gzip(data, { level: 9 }); return compressed; } // 使用示例 const originalData = 'Hello, world!'; const compressedData = compressToGzip(originalData); console.log(compressedData); 请注意,在大多数情况下,将GZIP压缩交给构建工具或服务器处理更为高效且合理。 前端代码中的压缩主要用于特定场景,比如需要动态生成并发送压缩数据的情况。

    check string for multiple substrings

    str = "your string"; str.match(/(our|ing)/g); ['our', 'ing'] terms = ["term1", "term2", "term3"] const str = "string to check for term1, term2" // check if the string has some of the terms result = terms.some(term => str.includes(term)) true // check if the string has all the terms result2 = terms.every(term => str.includes(term)) false

    Module Bundlers Guide



    A JavaScript bundler can be used when your project becomes too large for a single file or when you're working with libraries that have multiple dependencies. Module bundlers are the way to organize and combine many files of JavaScript code into one file.

    What is a JavaScript module bundler?

    A bundler is a development tool that combines many JavaScript code files into a single one that is production-ready loadable in the browser. A fantastic feature of a bundler is that it generates a dependency graph as it traverses your first code files. This implies that beginning with the entry point you specified, the module bundler keeps track of both your source files’ dependencies and third-party dependencies. Keeping all of the files and their dependencies up to date and ready was a herculean task for web developers. Consider a basic JavaScript CRUD (Create, Read, Update, and Delete) app like a grocery list. In the pre-bundler era, you might have constructed these functions in separate JS files. You could even opt to make your app a little more fancy by incorporating third-party libraries, and this would need your file to make several queries upon loading, like in this example. However, using a bundler will merge the files and their dependencies into a single file. Suppose you’re developing or maintaining a large app like an e-commerce site that provides access to thousands of products to several users. For a use case like this, you most likely will need to employ custom or third-party libraries to power some of your more complex tasks. In that case, developing without a JavaScript module bundler would make keeping all the dependencies updated to the latest version an exhaustive process. Apart from providing a consistent tooling environment that saves you from the pain of dependencies, many popular module bundlers also come with performance optimization features. Code splitting and hot module replacement are examples of these functionalities. JavaScript bundlers also have productivity-enhancing features such as robust error logging, which lets developers easily debug and repair errors.

    How does a bundler work?

    After discussing what bundlers are and how crucial they are in today's web development ecosystem, let's look at how these dependency management tools work. Overall, a bundler's operation is divided into two stages: dependency graph generation and eventual bundling.

     Mapping a Dependency Graph

    The first thing a module bundler does is generate a relationship map of all the served files. This process is called Dependency Resolution. To do this, the bundler requires an entry file which should ideally be your main file. It then parses through this entry file to understand its dependencies. Following that, it traverses the dependencies to determine the dependencies of these dependencies. Tricky, eh? It assigns unique IDs to each file it sees throughout this process. Finally, it extracts all dependencies and generates a dependency graph that depicts the relationship between all files. Why is this process necessary? It enables the module to construct a dependency order, vital for retrieving functions when a browser requests them. return { id, filename, dependencies, code, }; It prevents naming conflicts since the JS bundler has a good source map of all the files and their dependencies. It detects unused files allowing us to get rid of unnecessary files.

     Bundling

    After receiving inputs and traversing its dependencies during the Dependency Resolution phase, a bundler delivers static assets that the browser can successfully process. This output stage is called Packing. During this process, the bundler will leverage the dependency graph to integrate our multiple code files, inject the required function and module.exports object, and return a single executable bundle that the browser can load successfully.

    Top 5 JavaScript module bundlers

    Now that we’ve discussed the importance of JavaScript module bundlers and how they work, you might be wondering which kind of bundler is best for you. There are many different module bundlers in the JavaScript ecosystem and each with its unique bundling method. We'll look at five of the most popular module bundlers in the Javascript ecosystem, exploring how they function as well as their benefits and drawbacks.

     Webpack

    With over 18 million weekly downloads and 60k GitHub stars, Webpack is currently the most popular JavaScript module bundler. As a static module bundler, it comes with a host of sophisticated and highly customizable features, making it a module bundler for JavaScript files and a transformer, minifier, and optimizer of all types of file resources and assets. That’s not all. Webpack has a very rich plugin and loaders ecosystem as well.

      How does it work?

    Like all modern JavaScript bundlers, Webpack begins the bundling process by assembling a dependency graph. To understand how it performs the dependency resolution step, you must first grasp six key concepts: Entry: specifies where Webpack should initiate its dependency graph. You can have one or more entry points depending on your app’s architecture. Webpack iterates through the module(s) listed in the webpack.config.js config file identifying the entry point’s direct and indirect dependencies. module.exports = { entry: './app/index.js', }; Output: specifies the desired destination for the final output after Webpack completes the packing process. The Output property contains two sub-values: the file path, usually the /dist folder, and the desired filename. const path = require('path'); module.exports = { entry: './app/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'webpack-app.bundle.js', }, }; Loaders: allow Webpack to transform and bundle non-JS files. Plugins: allow Webpack to perform more advanced actions like custom resource optimization and management. Mode: allows Webpack to configure its operations to production or development modes dynamically. Browser Compatibility: allow Webpack to build bundles that support modern and old browsers with features like promises and polyfills. After creating the internal modules map, Webpack then uses functions to wrap the associated modules bundling all together to be invoked by one singular runtime function called webpackStart. Getting started is as simple as running npm i webpack

      Pros

       Multi-resource support
    In addition to providing out-of-the-box support for JS files, Webpack has a rich Plugin ecosystem it relies on to bundle other files like CSS and Images.
       Asset optimization
    Features like code-splitting allow you to break code files into chunks, thereby reducing load time. There’s the Hot module replacement that helps you to manage modules without fully reloading the browser. Developers can employ Loaders in preprocessing their files, resulting in a faster app runtime. These and more highly customizable optimization features have made Webpack the most popular JS bundler.
       Developers’ productivity
    When working with a complicated task like Module bundling as a developer, it’s crucial to have: Extensive documentation. A solid ecosystem of third-party tools you can lean on. Efficient error debugging process that makes your work easier. Webpack fulfills these three requirements by offering a massive ecosystem of plugins and loaders, as well as source map-powered debugging. That’s not all. Webpack has an internal caching system that empowers developers to build apps in a short time.

      Cons

       Complex
    Webpack’s sophistication is a double-edged sword for many developers who have a love-hate relationship with it. It also is complex and has a steep learning curve.
       Buggy and Slow
    Webpack’s all batteries included approach can sometimes cause Webpack app integrations to be overengineered. Over-reliance on plugins to do simple functions can cause the bundler to slow W necessitating technical debugging to make it well-optimized.

     Browserify

    Browserify is an open-source Javascript bundler that allows you to bundle Node.js files that the browser can run. With Browserify, developers can use node-style require() to load npm modules in the browser. Initially released in 2010, the JS bundler has enjoyed decent success amongst developers. It’s downloaded nearly 2 million times every week and has over 13k GitHub stars.

      How does it work?

    Like all other JavaScript bundlers, Browserify goes through defined stages when bundling modules. The first is the Dependency graph formation. In this stage, Browserify starts from the specified entry point files and then recursively searches for all require() calls in your files. Each require() call is resolved with a file path, and each file path is further traversed for more require() calls. After the entire app’s dependency graph has been fully mapped, it creates a self-contained bundle comprising files that have been merged and mapped to unique IDs. It's worth noting that Browserfy also offers advanced customizations, such as the ability to replace these IDs with hashed ones. You can then place the final bundle in a single <script> for eventual browser loading. Getting started with Browserify is as simple as running npm i webpack and running Browserify against your entry file. $ browserify main.js > bundle.js The bundler also provides some inbuilt options like --debug and --ignore-missing.

      Pros

       Simplicity
    For most applications with fewer features, many developers find Browserify perfect for their needs. It provides straightforward npm integrations that allow you to re-use your node code without needing a native CLI.
       Developers productivity
    Browserify’s most significant selling point is that it allows you to take advantage of the rich npm ecosystem. It's easy to learn and has excellent documentation. Furthermore, it comes with an inbuilt automatic build system that makes building modules fast and straightforward. All of this adds up to a great experience while developing your application.

      Cons

       No multi-resource support
    Unlike Webpack, Browserify doesn’t provide multi-asset support. You can, however, use a Gulp workflow to find your way around this. The process nevertheless introduces unnecessary complexity.
       Lack of advanced management features
    Browserify limits you to the Node.js npm ecosystem and lacks powerful asset management tools that can assist you in optimizing your modules. This includes a lack of support for dynamic loading.

     Parcel

    Parcel is a plug-and-play, zero-configuration build tool that allows developers to configure multi-assets quickly (e.g., JS, CSS, and HTML) modules necessary for development. It has over 39k stars on Github, making it the second most popular JS bundler behind Webpack.

      How does it work?

    Parcel’s bundling process involves three steps: Asset Tree construction: In this stage, Parcel takes an entry point asset and traverses through the file to identify the dependencies used to create a tree of assets similar to the dependency graph. Bundle Tree construction: Here, individual assets in the Asset Tree are combined with their linked dependencies to form a bundle tree. Packaging: This is the final stage where each bundle on the bundle tree is associated with its specific packager file types and transformed into a final compiled file. After that, you can then provide a single entry asset against Parcel. Make sure to note that Parcel supports multiple entry points. To get started, run npm i parcel. Let’s say you have a sample HTML boilerplate. <html> <body> <script src="./index.js"></script> </body> </html> You can then use Parcel to build the HTML file by running: parcel index.html. What’s impressive is that Parcel will compile the HTML file pointed to it and the index.js that the HTML links to.

      Pros

       Zero configuration
    Parcel solves the configuration issues faced with Webpack and Browserify providing developers with a performant architecture needed for rapid web development. There’s also multi-asset support like Webpack enabling bundles for all kinds of non-JavaScript assets like CSS, HTML, and images.
       Fast
    Parcel is fast providing premium resource optimization features like hot module replacement and lazy loading of split code. According to the most recent benchmarks, Parcel's bundling speed is 9.98s, compared to Browserify's 22.98s and Webpack's 20.71s. Using Parcel's built-in caching technique can even deliver quicker results, with a benchmark time of 2.64s.

      Cons

       Lack of advanced customizations
    As a highly-opinionated bundler, Parcel is perfect for small and medium-sized applications. Nonetheless, making it work for complex applications where you need to modify the configurations might be tedious. In this situation, most developers prefer to use Webpack.

     Fusebox

    Fusebox is an open-source Javascript and Typescript bundler and loader. It combines Webpack's best optimization techniques into a fast, lightweight bundler that gives a rich API experience.

      How does it work?

    The Fusebox bundling process provides a couple of defaults that keep things easy to get started without requiring extensive modifications. To get started, install Fusebox with the command: npm i fuse-box. After that, you need to create the main configuration script file, usually titled fuse.js or fuse.ts. Here's an example code snippet that includes the entry point and destination file, as well as the required mode. import { fusebox } from 'fuse-box'; fusebox({ target: 'browser', entry: 'src/index.tsx', webIndex: { template: 'src/index.html', }, devServer: true, }).runDev(); Fusebox initiates the bundling process by building a virtual file structure that mimics a dependency graph. These files are then emitted and bundled together.

      Pros

       Excellent developer experience
    Fusebox has a minimum defaults style resulting in a simple learning curve for beginners. This allows for a quick start without much configuration.
       Fast
    It provides a fast experience due to a couple of asset optimization features it has. Features like HMR (Hot Module Replacement) allow the bundler to manage assets without fully refreshing the browser. There’s a powerful cache system and inbuilt code-spilling, resulting in faster browser loads.

      Cons

       Poor multi-asset support
    Fusebox is Javascript and Typescript-centric, rendering inbuilt support for both files. Working with other files like CSS would require integrating the CSSPlugin or the SassPlugin. Because it is a newer bundler, it lacks the robust ecosystem seen in Webpack.

     Rollup

    Released in 2018, Rollup is a next-generation JavaScript bundler whose primary selling point is its tree-shaking feature, enabling it to sieve out unused resources before bundling single, smaller modules into larger ones. Because of this capability has gained some traction among developers and has been downloaded over 4 million times every week, and it also has more than 20,000 GitHub stars.

      How does it work?

    Rollup uses the main configuration file, usually named rollup.config.js, to define bundling specifications. Next, it analyzes the entry point file and then sorts the dependencies while creating a dependency order. During this parsing process, the tree shaking feature is also implemented. Finally, all the declared functions encountered in the specified modules are compiled into a single global scope while paying attention to potential name collision. To get started, run npm i rollup to install rollup. You can perform the bundling process either through a CLI with the aid of a config file or via the bundling JavaScript API. Here’s a sample config file containing the entry point, output file destination, and format type. export default { input: 'src/app.js', output: { file: 'bundle.js', format: 'cjs' } }; Like many other JavaScript bundlers, Rollup also supports multiple entry points.

      Pros

       Asset optimization
    Rollup provides rich asset management features allowing you to code-split your bundles for faster browser loads. There’s also the Tree-shaking feature that helps developers get rid of unnecessary variables or functions.
       Native ES6 support
    For better browser compatibility in sharing imports and exports, Javascript’s ES6 version was released. Rollups supports this new ES6 module system keeping existing import and export functions while allowing you to transform them to other module formats like CommonJS and AMD.

      Cons

       Budding developer ecosystem
    One of the growing pains of a new development tool is the time it takes to build a fully-fledged ecosystem. While Rollup is ideal for quick tasks, developers may be disappointed when creating large, complex apps due to a lack of plugins for required functionalities.

    Honorary Mention: Vite.js

    Vite.js

    Vite.js is a next-generation, open-source frontend building tool. Vite.js is a next-generation, open-source frontend building tool. Vue.js creator Evan You created Vite.js in 2020 to enhance the bundling ecosystem by exploiting the latest ES modules improvements to solve some of the building performance issues prior bundlers encountered.  Currently, Vite.js has over 33.9k stars on Github and has over 340,000 downloads every week.

       How Does It Work?

    One of Vite.js's unique features is that it comes with a dev server and a bundling build command. The Dev server parses your application modules and separates them into two groups: The dependencies which are mostly not frequently updated are pre-bunded using esbuild, a JavaScript bundler that's extremely faster than Webpack, Rollup, and Parcel. The application source code's other group requires frequent updates and is served on-demand without bundling to the browser leveraging the browser's powerful ESM module capability.  On the other hand, the build command bundles your code using Rollup, a JS bundler we've examined earlier. Vite.js starts from an entry point when traversing your codebase to convert them into production-ready static assets. Like several other JS bundlers, Vite.js also supports multiple entry points. // vite.config.js const { resolve } = require('path') const { defineConfig } = require('vite') module.exports = defineConfig({ build: { rollupOptions: { input: { main: resolve(__dirname, 'index.html'), nested: resolve(__dirname, 'nested/index.html') } } } })

      Pros 

       Lean and Fast
    By leveraging the Native ES6 module system, Vite.js can serve application code faster by reducing the number of browser requests it makes. That's not all. Vite.js also comes with Hot Module Replacement (HMR), making editing a quicker, near-instant process. 
       Multi-Framework Support 
    Vite.js is framework-agnostic with out-of-box support for many popular Javascript frameworks like React.js, Vue.js, Typescript, and Preact. Recent releases have also integrated support for CSS modules, pre-processors, and other static assets. For example, you can quickly set up a Vue.js app with Vite using the following command: npm init vite@latest my-vue-app -- --template vue It also has a rich plugin ecosystem that leverages other bundlers like esbuild and Rollup plugin ecosystems to provide developers with an extensive set of options.

      Cons

       Reliance on ESM Modules
    Vite.js heavily relies on the browser's native ESM system to produce the mindblowing speed it's known for. This means developers might run into issues when dealing with older browsers that don't support these upgrades.

    Closing thoughts

    Honestly, it's tough to determine which of these bundlers is the best overall because each offers distinctive features that may be ideal for your requirements. For example, if you're creating a large app with complex features, such as an e-commerce app, and want complete control over your configurations, Webpack is a fantastic option. On the other hand, Fusebox might be an attractive alternative if you're developing a hobby project and enjoy working with Typescript. I’d say that regardless of the option you take, performance and development workflow metrics should be your north star.

    Sound.js 开源音频库



    无论是游戏、教育应用还是交互式网站,音频都是不可或缺的元素。 Sound.js,能够简化网络音频的处理,让开发者能够更加专注于创造出色的音频体验。

    Sound.js 是什么?

    Sound.js 提供了一个统一的 API 来处理不同浏览器中的音频播放。 支持 Web Audio API、HTML5 Audio、Cordova/PhoneGap,并且提供了 Flash 作为后备选项。 开发者无需担心浏览器兼容性问题,可以轻松地在任何设备上播放音频。 特点 1. 跨浏览器支持:能够在所有现代浏览器上运行,包括 Chrome、Firefox、Safari、Opera 和 Internet Explorer。 2. 事件驱动:提供了一个事件驱动的音频播放模型,可以监听音频播放状态的变化,如播放完成、错误等。 3. 预加载和缓存:支持音频的预加载和缓存,确保音频文件在播放时无需等待在、加载。 4. 音量控制:提供简单的API来控制音量,包括静音和调节音量大小。 5. 多种音频格式:支持多种音频格式,如 MP3、OGG 等。

    快速开始

    要开始使用 Sound.js,需要做的第一件事就是将库文件引入到你的项目中。 以下是如何快速启动一个简单的音频播放示例: 1. 下载Sound.js:你可以从 GitHub 仓库下载 Sound.js。 2. 引入Sound.js:在你的HTML文件中引入 Sound.js 库。 <script src="path/to/soundjs.min.js"></script> 3. 编写JavaScript代码:创建一个简单的音频播放脚本。 // 预加载音频文件 createjs.Sound.registerSound("path/to/your-audio-file.mp3", "exampleSound"); // 播放音频 createjs.Sound.play("exampleSound"); 4. 运行项目:打开你的 HTML 文件,你应该能够听到音频播放。 下面是一个游戏示例

    应用案例

    Sound.js 可以用于多种场景,例如: • 游戏开发:在游戏中播放背景音乐和音效。 • 多媒体应用:在教育或娱乐应用中播放音频内容。 • 交互式网站:在网站中添加音频反馈,提升用户体验。

    最佳实践

    预加载音频:使用 createjs.Sound.registerSound 方法预加载音频文件,以避免播放时的延迟。 • 事件监听:利用 Sound.js 的事件系统,监听音频播放状态的变化,如 complete 事件表示音频播放完成。 • 音量控制:使用 setVolume 方法控制音频的音量,提供更好的用户体验

    生态项目

    Sound.js 是 CreateJS 生态系统的一部分,与其紧密相关的项目包括: • EaselJS:用于处理图形和动画的库,与 Sound.js 结合使用,创建丰富的多媒体应用。 • TweenJS:用于创建补间动画的库,与 Sound.js 结合使用,实现动画和音频的同步。

    locate all marks

    var historyBookstoc = $('#historyBookstoc'); var bookmarkerList = [] $("k").each(function(i) { var booktopic = $(this), booktopicNumber = i; booktopicLength = booktopicNumber +1; // make a content list var bookmarkerContent = $(this).text(); bookmarkerList.push(bookmarkerContent); // historyBookstoc coding here if (typeof(showbookTopicNumber) !== 'undefined'){ if (showbookTopicNumber == true){ historyBookstoc.append(booktopicNumber +' '+booktopic.html()+''+booktopicEnd); }else{ historyBookstoc.append(''+booktopic.html()+''+booktopicEnd); } }else{ historyBookstoc.append(''+booktopic.html()+'
    '); } // historyBookstoc.append(booktopicNumber +' '+booktopic.html()+'
    '); // modify the target id booktopic.attr('id', 'booktopic-' + booktopicNumber); booktopic.after(' 
    ') });

    regex replace multiple matches

    lastamt = Number(lastamt.replace(/^.*?;|w.*/g, "").replace(/,/g, ""))

    load extenal data

    .load

    $("#codelist").load("HKCodelist.txt")

    .get

    $("button").click(function(){ $.get("demo_test.asp", function(data, status){ console.log("Data: " + data + "\nStatus: " + status); }); }); thisImgHead = "<img src='http://charts.aastocks.com/servlet/Charts?fontsize=12&15MinDelay=F&lang=1&titlestyle=1&vol=1&Indicator=9&indpara1=20&indpara2=2&indpara3=0&indpara4=0&indpara5=0&subChart1=3&ref1para1=5&ref1para2=10&ref1para3=3&subChart2=3&ref2para1=12&ref2para2=26&ref2para3=9&subChart3=12&ref3para1=0&ref3para2=0&ref3para3=0&scheme=3&com=100&chartwidth=580&chartheight=400&stockid="; thisImgPCode= "&period=7"; thisImgTail="&type=1&logoStyle=1' "; $.get('5FC.txt', function(data) { var theList = data.split(','); $("#codelist").append("Total: " + theList.length + "<br>"); for(var codeNo = 0; codeNo < theList.length; codeNo++){ theText = theList[codeNo]; theFunccode = thisImgHead + theText + thisImgPCode + thisImgTail + "onclick = \"sCt('" + theText + "')\">"; $( "#codelist" ).append( theFunccode); }; }); Access to XMLHttpRequest at from origin 'null' has been blocked by CORS policy

    Video Streaming with JavaScript



    https://medium.com/@likovalevl/video-streaming-with-javascript-the-easy-way-45ecd7ec3f08 client creates video => client sends video to server => server stores video => client asks server for video => server loads the video from storage => server sends video to client => client plays video Everything happens with HTTP and doesn’t involve any superfluous code. Let’s start with the client-side. The root of the whole project will be the <video> HTML tag.

    create index.html

    like this: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Streaming</title> </head> <body> <video autoplay></video> <script src="index.js"></script> </body> </html> We’ve added <video> tag with autoplay attribute and <script> to hook our index.js from the directory root. Place the index.js in the same directory.

    To enable the camera

    we need to ask the browser if it has a proper API. For this we use the following function: function permittedGetUserMedia() { return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia); } So at the top level of the index.js we make a trigger: if (permittedGetUserMedia()) { const video = document.querySelector('video'); const mediaSource = new MediaSource(); video.src = URL.createObjectURL(mediaSource); navigator.mediaDevices.getUserMedia({ video: true }).then((stream) => processStream(stream, mediaSource)); } In this part of code, we check if we have access to the camera, then we get the node of <video> tag. This node has the src attribute. Typically it should be a URL of the video file, but today we will provide a virtual URL of some object in the browser memory. We create MediaSource and create its URL, that we set as video.url property. This MediaSource will provide the proper interface for <video> node. With the last directive, we will ask the user for permission to enable the camera. Users will see a notification in a browser and can allow video recording. If she or he did it, the promise that is returned by this method will be resolved and we will receive MediaStream object. In this example, we will pass it to the processStream function along with the MediaSource instance. In fact, all the rest of the actions here are in vain if you just want to make a cyberpunk mirror. You can just make (stream) => {video.srcObject = stream} without even bothering about MediaSource. This is also a viable approach. But here we are going to simulate the later connection to the server.

    processStream

    In processStream we write: function processStream(stream, mediaSource) { const mediaRecorder = new MediaRecorder(stream) const videoBuffer = mediaSource.addSourceBuffer('video/webm;codecs=vp8'); mediaRecorder.ondataavailable = (data) => { let fileReader = new FileReader(); let arrayBuffer; fileReader.onloadend = () => { arrayBuffer = fileReader.result; videoBuffer.appendBuffer(arrayBuffer) } fileReader.readAsArrayBuffer(data.data); } mediaRecorder.start() setInterval(() => { mediaRecorder.requestData() }, 1000) } Here we define MediaRecord instance that will create a kind of media file that we can send to the server later. MediaRecord must be started before use.

    VideoBuffer

    VideoBuffer is a special object that works as an input to MediaSource. It is an instance of MediaBuffer. You can have several MediaBuffers for one MediaSource. Right now MediaRecord just creates a bunch of video information. We can pull if from time to time to send to the server /video player. For this, we invoke requestData method that activates a built-in method of MediaRecorder called ondataavailable. It also cleans previous data so we can call it several times and receive non-overlapping bunches of video. For periodical loads of data, we can use setInterval. All the further magic will happen in MediaRecorder.ondataavailable. This method receives old data. We will feed it to our videoBuffer — and everything works. Except for one little thing: we need to convert the data into arrayBuffer using FileReader instance. This is basically it. We received the same cyberpunk mirror but with a little lag. Please, don’t try to shave or apply makeup using it. <

    server-side

    Now we can move to create the server-side. Let’s be lazy here and use docker-compose for faster connection of all services. For me the project structure looks like this: The rest of the files are autogenerated. I will not go deeper into the environment implementation, I just will show you the contents of the supporting files. Docker-compose creates 3 services: frontend, backend, and nginx. The last one makes sure that we have the same domain name for API and client: version: '3' services: nginx: image: nginx ports: - 80:80 restart: always volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/default.conf:/etc/nginx/conf.d/default.conf frontend: image: nginx volumes: - ../frontend:/usr/share/nginx/html backend: build: ./backend volumes: - ../backend:/app working_dir: /app command: nodemon index.js Nginx configurations are pretty standard, except I’ve made max body size a little bigger: user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; client_max_body_size 50m; sendfile on; keepalive_timeout 65; gzip on; include /etc/nginx/conf.d/*.conf; } The default site config is like this: upstream frontend-upstream { server frontend:80; } upstream backend-upstream { server backend:3000; } server { listen 80 default; server_name _; root /var/www/html; location ~ ^/api { rewrite ^/api/?(.*) /$1 break; proxy_pass http://backend-upstream; } location / { proxy_pass http://frontend-upstream; } } We set up upstreams for API and client here. Docekrfile for backend looks like this: FROM node RUN npm install nodemon -g For the sake of development simplicity, I set up nodemon here for hot-reloading the code. Now to the backend. I’ve used this package.json: { "name": "stream-test", "version": "1.0.0", "description": "", "main": "index.js", "dependencies": { "express": "^4.17.1", "express-fileupload": "^1.1.6-alpha.6" }, "devDependencies": {}, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC" }

    express

    It has only 2 dependencies: express and express-fileupload. With a pure node making the same will be a more painful process. Believe me, I’ve tried. Put empty index.js file into the backend directory, so on the first start backend container wouldn’t exit with an error. Use docker-compose up to set up the server and access the backend with docker-compose exec backend bash. From there execute npm install and we’re ready for coding. Prerequisites: For the frontend part, we will have the same functions permittedGetUserMedia, processStream, and the same if clause that we used before. We will change only processStream. For the backend we will need an obligatory part of express.js: const fs = require('fs') const bodyParser = require('body-parser') const express = require('express') const fileUpload = require('express-fileupload') const app = express() app.use(bodyParser.urlencoded()) app.use(bodyParser.json()) app.use(fileUpload({ useTempFiles: true, tempFileDir: '/tmp/' })) const hostname = '0.0.0.0' const port = 3000 // CODE GOES HERE app.listen(port, hostname, () => { console.log('Starting development server') })

    file upload

    Let’s start with file upload. From the frontend point of view, we need to grab the video and send it to the server. We can delete all contents of processStream function now and leave only a call of a new function called registerRecord. This function will look like this: function registerRecord(stream) { const mediaRecorder = new MediaRecorder(stream) let countUploadChunk = 0 mediaRecorder.ondataavailable = (data) => { sendFile(data.data, countUploadChunk) countUploadChunk++ } mediaRecorder.start() setInterval(() => { mediaRecorder.requestData() }, 2000) } We’re creating the same MediaRecorder instance and define a counter. The counter will be used to mark a new part of the video we send to the server. We’re using MediaRecorder instance the same way as before, except now we don’t put the result directly to the player, but send it to the server. We grow counter here to make a new chunk name every time. One step aside here. We will need to name our stream somehow. The name must be unique and the easiest way is to define it on the client-side. I’ve defined it as a global constant: function sendFile(file, chunkNumber) { const formData = new FormData(); formData.append('file', file); formData.append('name', STREAM_NAME); formData.append('chunk', chunkNumber); fetch('/api/upload', { method: 'PUT', body: formData }); }

    sendFile

    The sendFile function will look like this: function sendFile(file, chunkNumber) { const formData = new FormData(); formData.append('file', file); formData.append('name', STREAM_NAME); formData.append('chunk', chunkNumber); fetch('/api/upload', { method: 'PUT', body: formData }); } Nothing special here: we’re just sending a bunch of form-data including the file itself, name of stream and number of a chunk. Now we are sending video to the server at last. On backend let’s define a helper function: const makeDirnameFilename = (name, chunk) => { const dirname = `/app/uploads/${name}` const filename = `${dirname}/${chunk}.webm` return [dirname, filename] } It will help us to define the name of saving/loading files. Now we can work with uploading file: app.put('/upload', (req, res) => { const file = req.files.file const [dirname, filename] = makeDirnameFilename(req.body.name, req.body.chunk) fs.promises.mkdir(dirname, {recursive: true}) .then( file.mv(filename) ) res.statusCode = 200 res.setHeader('Content-Type', 'text/plain') res.end('Upload\n') }) First, we define some helper constants. Then, we make sure that the directory for the new file really exists. Our file is saved in temporary storage and we just move it to the permanent directory. This all happens asynchronously so we return the response before the file is actually saved. Now, if you will try the code, it will start saving files, but won’t show you anything. We proceed with playing functionality. For the frontend part, we will add a call of registerPlayer function in processStream function. Finally the later will look like this: function processStream(stream, mediaSource) { registerRecord(stream) registerPlayer(mediaSource) } And here is the whole code of the registerPlayer: function registerPlayer(mediaSource) { const videoBuffer = mediaSource.addSourceBuffer('video/webm;codecs=vp8'); let countDownloadChunk = 0 setInterval(() => { fetch(`/api/download?name=${STREAM_NAME}&chunk=${countDownloadChunk}`) .then((response) => { if (response.status !== 200) { throw Error('no such file') } return response.arrayBuffer() }).then((buffer) => { countDownloadChunk++ videoBuffer.appendBuffer(buffer) }).catch(() => {}) }, 1000) } We’re defining videoBuffer as before. And adding one more counter, this time for downloading. Downloading intervals will be less then uploading to make sure that we catch all new chunks of video without video freezes. With fetch, we grab the file on a specific route using the GET query. Then, if a response is 200 (we actually can have 204 here if a new file is not ready), we make arrayBuffer from file and return it as a next promise resolution. The resulting arrayBuffer we will send into videoBuffer. We increment the counter here only on a successful download. The last catch is used to prevent littering console with error messages. For the backend we define a new endpoint: app.get('/download', (req, res) => { const query = req.query const [dirname, filename] = makeDirnameFilename(query.name, query.chunk) fs.promises.readFile(filename) .then((file) => { res.statusCode = 200 res.write(file, 'binary') res.end() }).catch(() => { res.statusCode = 204 res.end() }) }) First, we create helper constants here and then trying to read the file. On success, we just send it to the client, but if we don’t find it — we return 204 for the client like a call to try it later. If you will return 404, which looks logical, the Chrome browser will show lots of errors in a console later. Keep in mind that we’re working with a file as with binary everywhere, so we provide binary flag on file save and response. Now you can open localhost/ in the browser and try the code yourself. If this didn’t work and you don’t see your picture in 3 seconds, just refresh the page. With current code may exist a little bug when the first chunk of code was not created and your player just can't load any further part. This bug can be fixed with 2 techniques that I recommend to use: using WebSocket for both uploading and downloading instead of HTTP requests and adding some file mapping that will tell the client which files it can download right now. But this goes far from the actual goal of this article. We’ve just created the real simple streaming workflow. This structure, workflow and, especially, work with browser API can be handy to understand the whole background of how modern streaming services work. To see the complete code visit the GitHub repo:https://github.com/hgato/streaming-article.

    stream from camera to web page

    The Live Streaming either need Streaming Video Server or HTTP Streaming.

    Streaming Video Server

    IT is the server from which you will stream your video. They have to be extremely fast, able to handle many connections at a time, depending on user's connection speed etc. To have this, you can Buy your own, or Sign up for a hosted streaming plan with an ISP (Internet Service Provider)

    HTTP Streaming

    Or, you need HTTP Streaming To make it as simple as it can be Create a video file in a common streaming media format Upload the file to your web server Make a simple hyperlink to the video file, or use special HTML tags to embed the video in a web page.

    Some helpful posts and plugins

    Video streaming over websockets using JavaScript jQuery Video Player: Enables webcam video streaming Video and Audio Streaming with Flash and Open Source Tools
    And yes <object> tag, can be used to embed a video player which stream the data. Streaming over HTTP with JavaScript: AJAX video player Recommended, step by step guide

    Access Device Camera using Camera API



    It doesn’t require any library or module to be installed. you can do this by just writing a small code.

    add a html5 video tag

    First, you have to add a html5 video tag to your index.html <video id="video"></video> In your camera.js file add the following code snippet.

    First, check if your browser is supporting navigator.mediaDevices

    if(navigator && navigator.mediaDevices){ //Your browser is supporting camera API. }else{ console.log("camera API is not supported by your browser") }

    add the camera API code

    In the next step, we will add the camera API code. if(navigator && navigator.mediaDevices){ navigator.mediaDevices.getUserMedia(options) .then(function(stream) { //use the stream to you code }) .catch(function(err) { //Handle error here }); }else{ console.log("camera API is not supported by your browser") }

    parameter options

    as you can see that in the above code there are parameter options. It's a configuration object which we will pass to restrict or allow some of its features. For example, to allow the audio: { audio: true } to access the front camera: { video: { facingMode: "user" } } to access the back camera: { video: { facingMode: { exact: "environment" } } } For more information about configuration, visit this doc.

    assign a stream

    We are almost done with the configuration, Now will assign a stream to the video tag. if(navigator && navigator.mediaDevices){ const options = { audio: false, video: { facingMode: "user", width: 200, height: 200 } } navigator.mediaDevices.getUserMedia(options) .then(function(stream) { var video = document.querySelector('video'); video.srcObject = stream; video.onloadedmetadata = function(e) { video.play(); }; }) .catch(function(err) { //Handle error here }); }else{ console.log("camera API is not supported by your browser") }

    capture the image

    So, We are almost done till now, now we will add a button to capture the image from the video and display it on canvas.

    final camera.js file

    This is our final camera.js file. var video, canvas, ctx; if(navigator && navigator.mediaDevices){ const options = { audio: false, video: { facingMode: "user", width: 300, height: 300 } } navigator.mediaDevices.getUserMedia(options) .then(function(stream) { video = document.querySelector('video'); video.srcObject = stream; video.onloadedmetadata = function(e) { video.play(); }; canvas = document.getElementById("myCanvas"); ctx = canvas.getContext('2d'); }) .catch(function(err) { //Handle error here }); }else{ console.log("camera API is not supported by your browser") } function clickPhoto() { ctx.drawImage(video, 0,0, canvas.width, canvas.height); } Here is our final index.html file. <body> <div style="text-align: center;"> <video id="video" style="text-align: center; border-radius: 20px;"></video> </div> <div style="text-align: center;"> <button type="button" class="btn btn-warning" onclick="clickPhoto();">Take Photo</button> </div> <div style="text-align: center;"> <canvas id="myCanvas" width="300" height="300" style="text-align: center; border-radius: 20px;"></canvas> </div> </body> Download the final codebase repo. See the demo here.

    Video Streaming Server

    https://github.com/thesmartcoder7/video_streaming_server

    Installation

    Clone this repository or download the source code. git clone https://github.com/thesmartcoder7/video-streaming-server.git From here, navigate to the project directory cd video-streaming-server Install the npm packages npm install

    Usage

    Place your video file (e.g., Chris-Do.mp4) in the root directory of the project. Start the server by running the following command: node server.js This will start the server, and you will see the message "Listening on port 8000!" in the console, indicating that the server is running. To access the video stream, open a web browser and navigate to http://localhost:8000/video. You should be able to stream the video.

    select column from a two dimensional array

    Use Array.prototype.map() with an arrow function: newObj = [ [1, 2, 3], [4, 5, 6], [7, 8, 9],]; arrayColumn = (newObj, n) => newObj.map(x => x[n]); arrayColumn(newObj, 1)

    crossorigin="anonymous"

    crossorigin attribute has only two possible values: anonymous or use-credentials. Any value other than anonymous, including empty value, will be translated to anonymous.

    video controlslist

    to customize Chrome's native media controls such as the download, fullscreen and remoteplayback buttons. The current implementation for now is a blocklist mechanism on native controls with the ability to set them directly from HTML content using the new attribute controlsList. controlslist Examples Usage in Javascript: var video = document.querySelector('video'); video.controls; // true video.controlsList; // "nofullscreen nodownload noremoteplayback noplaybackrate" - "foobar" not present video.controlsList.remove('noremoteplayback'); video.controlsList; // "nofullscreen nodownload noplaybackrate" - "noremoteplayback" not present video.getAttribute('controlslist'); // "nofullscreen nodownload noplaybackrate"

    detect triple click

    window.addEventListener('click', function(evt) { if (evt.detail === 3) { alert('triple click!'); $("body").toggleClass('stop-scrolling'); } }); No native event exists to capture 3 clicks in a row. Check the value of click property and see if it is 3: window.addEventListener('click', function(evt) { if (evt.detail === 3) { alert('triple click!'); } }); The best approach is to capture a double-click, followed by a triple-click for example: var timer, // timer required to reset timeout = 200; // timer reset in ms window.addEventListener("dblclick", function(evt) { timer = setTimeout(function() { timer = null; }, timeout); }); window.addEventListener("click", function(evt) { if (timer) { clearTimeout(timer); timer = null; executeTripleClickFunction(); } }); And you can even catch single, double, triple, ... clicks as you like. customizable click delay (timeout): var clicks = 0; var timer, timeout = 350; var doubleClick = function(e) { console.log('doubleClick'); } var tripleClick = function(e) { console.log('tripleClick'); } // click timer yourcontainer.addEventListener('click', function(e) { clearTimeout(timer); clicks++; var evt = e; timer = setTimeout(function() { if(clicks==2) doubleClick(evt); if(clicks==3) tripleClick(evt); clicks = 0; }, timeout); }); Working demo: http://jsfiddle.net/L6d0p4jo/

    to enable/disable elements

    The disabled attribute can be used on the following elements: button, fieldset, input, optgroup, option, select, textarea Return the disabled property: buttonObject.disabled Set the disabled property: buttonObject.disabled = true|false var x = document.getElementById("myBtn").disabled; $('button').disabled = true; var nodes = $('button') button[5].disabled=true; $('button').attr('disabled') $(this).attr({'disabled': 'disabled'}); nodes[3].disabled = 'disabled'; var nodes = $('button') nodes[5].style.display='none';

    to chop a string by space character

    str = '123 r' myArray = str.split(" "); // ['123', 'r'] to chop an array of strings by space character: str = ['123 r', '456 t'] myArray = str.map(item => item.split(' ')[0]); // ['123', '456']

    Range Sliders

    <input type="range" min="1" max="100" value="50" id="sliderRange"> Value: <span id="output"></span> var slider = document.getElementById("sliderRange"); // must use document.getElementById, jquery $ cannot work $("#output").text(slider.value) slider.oninput = function() { $("#output").text(slider.value)}

    高级JavaScript技巧



    高级JavaScript技巧,包括带别名的解构、柯里化、防抖、节流、记忆化、代理、生成器、控制台方法、结构化克隆和自调用函数。

    1. 带别名的解构

    解构允许您从数组中提取值或将对象的属性解包到不同的变量中。 别名功能使您能够在这一过程中重命名变量,这在处理来自外部源(如API)的数据时特别有用。 「用例」: 从API获取数据时,如果您想为属性赋予更有意义的名称,以提高代码的可读性和可维护性。 const apiResponse = { first_name: 'John', user_age: 30, address: { city: 'New York', zip: '10001' } }; const { first_name: firstName, user_age: age, address: { city: hometown, zip: postalCode } } = apiResponse; console.log(firstName); // John console.log(age); // 30 console.log(hometown); // New York console.log(postalCode); // 10001 「为何使用」: 它有助于使变量名称更具自解释性和直观性,从而提高代码的可读性和可维护性。 通过使用别名,您可以避免名称冲突,并提高代码的清晰度,使其更易于处理复杂的数据结构。

    2. 柯里化

    柯里化是将一个接受多个参数的函数转换为一系列每个都接受单个参数的函数的过程。 此技术允许您创建更灵活和可重用的函数,这在函数式编程中特别有用。 「用例」: 为应用折扣创建可重用和可配置的函数。 无需为不同的折扣百分比编写单独的函数,您可以创建一个单一的柯里化函数。 const applyDiscount = (discount) => (price) => price - (price * discount / 100); const tenPercentOff = applyDiscount(10); const twentyPercentOff = applyDiscount(20); console.log(tenPercentOff(100)); // 90 console.log(twentyPercentOff(100)); // 80 const applyTax = (taxRate) => (price) => price + (price * taxRate / 100); const applyTenPercentTax = applyTax(10); console.log(applyTenPercentTax(100)); // 110 console.log(applyTenPercentTax(twentyPercentOff(100))); // 88 「为何使用」: 它使您能够在函数中预设参数,从而实现更模块化和可组合的代码。 这可以极大地简化高度可重用实用函数的创建,使您的代码库更整洁且更易于维护。 柯里化在需要部分应用函数或使用不同配置重用函数的场景中特别有用。

    3. 防抖和节流

    防抖和节流是控制函数执行频率的技术。 它们对于优化事件处理程序以防止可能降低性能的过度函数调用特别有用。

    防抖

    防抖确保在上次调用后的特定时间段内不再再次调用函数。 这在诸如搜索输入字段之类的场景中很有用,您希望等到用户停止输入后再进行API调用。 「用例」: 优化搜索输入字段以减少API调用的数量。 这可以防止服务器过载,并通过仅在用户完成输入后启动搜索来改善用户体验。 function debounce(func, delay) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } const search = debounce((query) => { console.log(`Searching for ${query}`); // 想象这里有一个API调用 }, 300); document.getElementById('searchInput').addEventListener('input', (event) => { search(event.target.value); }); 「为何使用」: 通过确保函数仅在用户停止执行触发操作后调用,减少不必要的函数调用次数,提高性能和用户体验。 这对于涉及网络请求或繁重计算的操作特别有用。

    节流

    节流确保函数在指定的时间段内最多调用一次。 这在诸如滚动事件之类的场景中很有用,您希望限制函数调用的频率。 「用例」: 优化滚动事件处理以提高性能。 这可以防止浏览器因过多的事件调用而不堪重负,确保更流畅和响应更灵敏的交互。 function throttle(func, interval) { let lastCall = 0; return function(...args) { const now = Date.now(); if (now - lastCall >= interval) { lastCall = now; func.apply(this, args); } }; } const handleScroll = throttle(() => { console.log('Scrolled'); // 想象这里有复杂的计算或DOM更新 }, 300); window.addEventListener('scroll', handleScroll); 「为何使用」: 通过确保函数以受控的间隔调用,防止性能问题,减少浏览器的负载并提供更好的用户体验。 节流在诸如滚动或调整大小事件等可能频繁触发的事件监听器中特别有用。

    4. 记忆化

    记忆化是一种优化技术,涉及缓存昂贵函数调用的结果,并在再次出现相同输入时返回缓存的结果。 这可以显著提高具有繁重计算的函数的性能,特别是那些频繁使用相同参数调用的函数。 「用例」: 提高诸如斐波那契计算之类的递归函数的性能。 如果没有记忆化,对斐波那契函数的每次调用都会多次冗余地计算相同的值,导致指数级的时间复杂度。 const memoize = (fn) => { const cache = {}; return (...args) => { const key = JSON.stringify(args); if (!cache[key]) { cache[key] = fn(...args); } return cache[key]; }; }; const fibonacci = memoize((n) => { if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2); }); console.log(fibonacci(40)); // 102334155 「为何使用」: 避免冗余计算,显著提高具有重复输入的函数的性能。 记忆化可以将低效、重复的计算转换为可管理的线性时间操作,使其成为优化性能密集型任务的基本技术。

    5. 代理

    Proxy对象允许您为另一个对象创建代理,使您能够拦截和重新定义基本操作,例如属性查找、赋值、枚举、函数调用等。 这为向对象添加自定义行为提供了一种强大的方式。 「用例」: 在对象属性访问和赋值时进行验证和日志记录。 例如,您可以强制类型约束并记录访问尝试,提供更好的控制和调试功能。 const user = { name: 'John', age: 30 }; const handler = { get: (target, prop) => { console.log(`Getting ${prop}`); return target[prop]; }, set: (target, prop, value) => { if (prop === 'age' & typeof value !== 'number') { throw new TypeError('Age must be a number'); } console.log(`Setting ${prop} to ${value}`); target[prop] = value; return true; } }; const proxyUser = new Proxy(user, handler); console.log(proxyUser.name); // Getting name, John proxyUser.age = 35; // Setting age to 35 // proxyUser.age = '35'; // Throws TypeError 「为何使用」: 允许为对象操作自定义行为,例如验证、日志记录等,增强对对象操作的控制。 代理还可用于实现诸如访问控制和数据绑定之类的复杂逻辑。 这使其成为管理和扩展对象行为的多功能工具。

    6. 生成器

    生成器是可以退出然后再重新进入的函数,在重新进入时能保持其上下文和变量绑定。 它们对于实现迭代器和以类似同步的方式处理异步任务很有用。 「用例」: 为自定义对象遍历实现迭代器。 生成器为定义自定义迭代行为提供了一种简单的方式,使遍历复杂数据结构变得更容易。 function* objectEntries(obj) { for (let key of Object.keys(obj)) { yield [key, obj[key]]; } } const user = { name: 'John', age: 30, city: 'New York' }; for (let [key, value] of objectEntries(user)) { console.log(`${key}: ${value}`); } // name: John // age: 30 // city: New York 「为何使用」: 为实现自定义迭代器和简化异步工作流提供了强大的工具。 生成器使处理复杂的迭代逻辑和异步进程变得更容易,从而导致更具可读性和可维护性的代码。 它们还可以用于诸如使用co之类的库以更直接、线性的方式管理异步操作等任务。

    7. 善用控制台

    「用例」: 改进复杂对象的调试日志记录。 诸如console.table、console.group和console.time等控制台方法可以提供更结构化和信息丰富的调试信息。 // 基本日志记录 console.log('Simple log'); console.error('This is an error'); console.warn('This is a warning'); // 记录表格数据 const users = [ { name: 'John', age: 30, city: 'New York' }, { name: 'Jane', age: 25, city: 'San Francisco' }, ]; console.table(users); // 分组日志 console.group('User Details'); console.log('User 1: John'); console.log('User 2: Jane'); console.groupEnd(); // 计时代码执行 console.time('Timer'); for (let i = 0; i < 1000000; i++) { // 一些繁重的计算 } console.timeEnd('Timer'); 「为何使用」: 增强了调试信息的可见性和组织性,使诊断和修复问题变得更容易。 正确使用控制台方法可以通过提供清晰、有组织和详细的日志显著提高调试过程的效率。

    8. 使用structuredClone进行结构化克隆

    使用新的structuredClone进行深度克隆对象。 与传统的浅拷贝不同,结构化克隆创建对象的深度副本,确保嵌套对象也被复制。 此方法避免了JSON.parse(JSON.stringify(obj))的限制,后者无法处理诸如函数、未定义和循环引用等某些数据类型。 「用例」: 创建复杂对象的深度副本。 当您需要复制对象以进行不应更改原始数据的操作时很有用。 const obj = { a: 1, b: { c: 2 }, date: new Date(), arr: [1, 2, 3], nestedArr: [{ d: 4 }] }; const clonedObj = structuredClone(obj); console.log(clonedObj); // { a: 1, b: { c: 2 }, date: 2023-06-08T00:00:00.000Z, arr: [1, 2, 3], nestedArr: [{ d: 4 }] } console.log(clonedObj === obj); // false console.log(clonedObj.b === obj.b); // false console.log(clonedObj.date === obj.date); // false console.log(clonedObj.arr === obj.arr); // false console.log(clonedObj.nestedArr[0] === obj.nestedArr[0]); // false 「为何使用」: 提供了一种内置、高效的对象深度克隆方式,避免了手动深度拷贝实现的陷阱和复杂性。 此方法比诸如JSON.parse(JSON.stringify(obj))之类的替代方法更可靠,并且能更好地处理复杂的数据结构。

    9. 自调用函数

    自调用函数,也称为立即调用函数表达式(IIFE),在创建后会自动执行。 它们对于封装代码以避免污染全局作用域很有用,这对于维护干净和模块化的代码至关重要。 「用例」: 封装代码以避免污染全局作用域。 此技术在较旧的JavaScript环境(其中块作用域(let和const)不可用)或需要立即执行初始化逻辑的场景中特别有用。 (function() { const privateVar = 'This is private'; console.log('Self-invoking function runs immediately'); // 初始化代码在此处 })(); // 私有变量无法从外部访问 // console.log(privateVar); // ReferenceError: privateVar is not defined 「为何使用」: 通过避免全局变量和在全局作用域中不留下痕迹地执行初始化代码来帮助维护干净的代码。 这种方法可以防止在较大的代码库中发生冲突,并确保更好地封装功能,提高代码的可维护性并避免副作用。

    10. 带标签的模板字面量

    带标签的模板字面量允许您自定义模板字面量的处理方式。 它们对于创建专门的模板很有用,例如用于国际化、清理HTML或生成动态SQL查询。 「用例」: 在HTML模板中清理用户输入以防止XSS攻击。 此技术确保用户生成的内容安全地插入到DOM中,而不会执行任何恶意脚本。 function sanitize(strings, ...values) { return strings.reduce((result, string, i) => { let value = values[i - 1]; if (typeof value === 'string') { value = value.replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } return result + value + string; }); } const userInput = '<script>alert("xss")</script>'; const message = sanitize`User input: ${userInput}`; console.log(message); // User input: <script>alert("xss")</script> 「为何使用」: 提供了一种强大的机制来控制和自定义模板字面量的输出,实现更安全和更灵活的模板创建。 带标签的模板字面量可用于加强安全性、格式化字符串和生成动态内容,增强代码的健壮性和通用性。

    结论

    JavaScript是一门具有丰富特性的语言,可以帮助您编写更干净、更高效的代码。 通过将这些高级技巧纳入您的编码实践中,您可以提高生产力并增强代码的可读性。 从带别名的解构到柯里化、防抖、节流等等,这些技巧可以使您的代码更干净、更高效。 原文地址:https://medium.com/@bjprajapati381/10-advanced-javascript-tricks-you-dont-know-f1929e40703d

    Advanced JavaScript Tricks

    JavaScript is a versatile language with many hidden features that can make your development process more efficient and your code cleaner. Here are 10 advanced JavaScript tricks that you might not know, but which can significantly enhance your coding skills.

    1. Destructuring with Aliasing

    Destructuring allows you to unpack values from arrays or properties from objects into distinct variables. Aliasing enables you to rename the variables during this process, which is particularly useful when dealing with data from external sources like APIs. Use Case: When fetching data from an API, and you want to give more meaningful names to the properties for better code readability and maintainability. const apiResponse = { first_name: 'John', user_age: 30, address: { city: 'New York', zip: '10001' } }; const { first_name: firstName, user_age: age, address: { city: hometown, zip: postalCode } } = apiResponse; console.log(firstName); // John console.log(age); // 30 console.log(hometown); // New York console.log(postalCode); // 10001 Why Use It: It helps in making the variable names more self-explanatory and intuitive, which improves code readability and maintenance. By using aliasing, you can avoid name clashes and enhance the clarity of your code, making it easier to work with complex data structures.

    2. Currying

    Currying is the process of transforming a function that takes multiple arguments into a series of functions that each take a single argument. This technique allows you to create more flexible and reusable functions, which can be particularly useful in functional programming. Use Case: Create reusable and configurable functions for applying discounts. Instead of writing separate functions for different discount percentages, you can create a single curried function. const applyDiscount = (discount) => (price) => price - (price * discount / 100); const tenPercentOff = applyDiscount(10); const twentyPercentOff = applyDiscount(20); console.log(tenPercentOff(100)); // 90 console.log(twentyPercentOff(100)); // 80 const applyTax = (taxRate) => (price) => price + (price * taxRate / 100); const applyTenPercentTax = applyTax(10); console.log(applyTenPercentTax(100)); // 110 console.log(applyTenPercentTax(twentyPercentOff(100))); // 88 Why Use It: It enables you to preset arguments in functions, leading to more modular and composable code. This can greatly simplify the creation of highly reusable utility functions, making your codebase cleaner and easier to maintain. Currying is especially useful in scenarios where functions need to be partially applied or reused with different configurations.

    3. Debouncing and Throttling

    Debouncing and throttling are techniques to control how often a function is executed. They are particularly useful for optimizing event handlers to prevent excessive function calls that can degrade performance. Debouncing: Debouncing ensures that a function is not called again until a certain amount of time has passed since the last call. This is useful for scenarios like search input fields where you want to wait until the user has stopped typing before making an API call. Use Case: Optimizing a search input field to reduce the number of API calls. This can prevent server overload and improve the user experience by only initiating the search once the user has finished typing. function debounce(func, delay) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } const search = debounce((query) => { console.log(`Searching for ${query}`); // Imagine an API call here }, 300); document.getElementById('searchInput').addEventListener('input', (event) => { search(event.target.value); }); Why Use It: Reduces the number of unnecessary function calls, improving performance and user experience by ensuring that the function is only called after the user has stopped performing the triggering action. This is particularly useful for actions that involve network requests or heavy computations. Throttling: Throttling ensures that a function is called at most once in a specified time period. This is useful for scenarios like scroll events where you want to limit the frequency of function calls. Use Case: Optimizing scroll event handling to improve performance. This can prevent the browser from being overwhelmed by too many event calls, ensuring smoother and more responsive interactions. function throttle(func, interval) { let lastCall = 0; return function(...args) { const now = Date.now(); if (now - lastCall >= interval) { lastCall = now; func.apply(this, args); } }; } const handleScroll = throttle(() => { console.log('Scrolled'); // Imagine complex calculations or DOM updates here }, 300); window.addEventListener('scroll', handleScroll); Why Use It: Prevents performance issues by ensuring a function is called at controlled intervals, reducing the load on the browser and providing a better user experience. Throttling is particularly useful for event listeners that can be triggered frequently, such as scroll or resize events.

    4. Memoization

    Memoization is an optimization technique that involves caching the results of expensive function calls and returning the cached result when the same inputs occur again. This can significantly improve performance for functions with heavy computation, particularly those that are called frequently with the same arguments. Use Case: Improve performance of recursive functions like Fibonacci calculation. Without memoization, each call to the Fibonacci function would redundantly compute the same values multiple times, leading to exponential time complexity. const memoize = (fn) => { const cache = {}; return (...args) => { const key = JSON.stringify(args); if (!cache[key]) { cache[key] = fn(...args); } return cache[key]; }; }; const fibonacci = memoize((n) => { if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2); }); console.log(fibonacci(40)); // 102334155 Why Use It: Avoids redundant calculations, significantly improving performance for functions with repeated inputs. Memoization can transform an inefficient, repetitive computation into a manageable, linear-time operation, making it an essential technique for optimizing performance-intensive tasks.

    5. Proxy

    The Proxy object allows you to create a proxy for another object, enabling you to intercept and redefine fundamental operations such as property lookup, assignment, enumeration, function invocation, etc. This provides a powerful way to add custom behavior to objects. Use Case: Validation and logging on object property access and assignment. For instance, you can enforce type constraints and log access attempts, providing better control and debugging capabilities. const user = { name: 'John', age: 30 }; const handler = { get: (target, prop) => { console.log(`Getting ${prop}`); return target[prop]; }, set: (target, prop, value) => { if (prop === 'age' & typeof value !== 'number') { throw new TypeError('Age must be a number'); } console.log(`Setting ${prop} to ${value}`); target[prop] = value; return true; } }; const proxyUser = new Proxy(user, handler); console.log(proxyUser.name); // Getting name, John proxyUser.age = 35; // Setting age to 35 // proxyUser.age = '35'; // Throws TypeError Why Use It: Allows custom behavior for object operations, such as validation, logging, and more, enhancing control over object manipulation. Proxies can also be used to implement complex logic like access control and data binding. This makes them a versatile tool for managing and extending the behavior of objects.

    6. Generators

    Generators are functions that can be exited and later re-entered, maintaining their context and variable bindings across re-entrances. They are useful for implementing iterators and handling asynchronous tasks in a synchronous-like manner. Use Case: Implementing an iterator for custom object traversal. Generators provide a simple way to define custom iteration behavior, making it easier to traverse complex data structures. function* objectEntries(obj) { for (let key of Object.keys(obj)) { yield [key, obj[key]]; } } const user = { name: 'John', age: 30, city: 'New York' }; for (let [key, value] of objectEntries(user)) { console.log(`${key}: ${value}`); } // name: John // age: 30 // city: New York Why Use It: Provides a powerful tool for implementing custom iterators and simplifying asynchronous workflows. Generators make it easier to handle complex iteration logic and asynchronous processes, leading to more readable and maintainable code. They can also be used for tasks like managing asynchronous operations in a more straightforward, linear fashion using libraries like co.

    7. Making Good Use of Console

    Use Case: Improve logging for debugging complex objects. The console methods like console.table, console.group, and console.time can provide more structured and informative debug information. // Basic logging console.log('Simple log'); console.error('This is an error'); console.warn('This is a warning'); // Logging tabular data const users = [ { name: 'John', age: 30, city: 'New York' }, { name: 'Jane', age: 25, city: 'San Francisco' }, ]; console.table(users); // Grouping logs console.group('User Details'); console.log('User 1: John'); console.log('User 2: Jane'); console.groupEnd(); // Timing code execution console.time('Timer'); for (let i = 0; i < 1000000; i++) { // Some heavy computation } console.timeEnd('Timer'); Why Use It: Enhances the visibility and organization of debugging information, making it easier to diagnose and fix issues. Proper use of console methods can significantly improve the efficiency of your debugging process by providing clear, organized, and detailed logs.

    8. Structured Cloning with structuredClone

    Deep clone objects using the new structuredClone. Unlike the traditional shallow copy, structured cloning creates a deep copy of the object, ensuring that nested objects are also copied. This method avoids the limitations of JSON.parse(JSON.stringify(obj)), which cannot handle certain data types like functions, undefined, and circular references. Use Case: Creating a deep copy of complex objects. This is useful when you need to duplicate objects for operations that should not mutate the original data. const obj = { a: 1, b: { c: 2 }, date: new Date(), arr: [1, 2, 3], nestedArr: [{ d: 4 }] }; const clonedObj = structuredClone(obj); console.log(clonedObj); // { a: 1, b: { c: 2 }, date: 2023-06-08T00:00:00.000Z, arr: [1, 2, 3], nestedArr: [{ d: 4 }] } console.log(clonedObj === obj); // false console.log(clonedObj.b === obj.b); // false console.log(clonedObj.date === obj.date); // false console.log(clonedObj.arr === obj.arr); // false console.log(clonedObj.nestedArr[0] === obj.nestedArr[0]); // false Why Use It: Provides a built-in, efficient way to perform deep cloning of objects, avoiding the pitfalls and complexities of manual deep copy implementations. This method is more reliable and handles complex data structures better than alternatives like JSON.parse(JSON.stringify(obj)).

    9. Self-Invoking Functions

    Self-invoking functions, also known as Immediately Invoked Function Expressions(IIFE), are executed automatically after they are created. They are useful for encapsulating code to avoid polluting the global scope, which is essential in maintaining clean and modular code. Use Case: Encapsulating code to avoid polluting the global scope. This technique is particularly useful in older JavaScript environments where block scope (let and const) is not available, or in scenarios where immediate execution is needed for initialization logic. (function() { const privateVar = 'This is private'; console.log('Self-invoking function runs immediately'); // Initialization code here })(); // Private variables are not accessible from outside // console.log(privateVar); // ReferenceError: privateVar is not defined Why Use It: Helps in maintaining clean code by avoiding global variables and executing initialization code without leaving traces in the global scope. This approach can prevent conflicts in larger codebases and ensure better encapsulation of functionality, improving code maintainability and avoiding side effects.

    10. Tagged Template Literals

    Tagged template literals allow you to customize the way template literals are processed. They are useful for creating specialized templates, such as for internationalization, sanitizing HTML, or generating dynamic SQL queries. Use Case: Sanitizing user input in HTML templates to prevent XSS attacks. This technique ensures that user-generated content is safely inserted into the DOM without executing any malicious scripts. function sanitize(strings, ...values) { return strings.reduce((result, string, i) => { let value = values[i - 1]; if (typeof value === 'string') { value = value.replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } return result + value + string; }); } const userInput = '<script>alert("xss")</script>'; const message = sanitize`User input: ${userInput}`; console.log(message); // User input: <script>alert("xss")</script> Why Use It: Provides a powerful mechanism to control and customize the output of template literals, enabling safer and more flexible template creation. Tagged template literals can be used to enforce security, format strings, and generate dynamic content, enhancing the robustness and versatility of your code.

    disable or enable buttons using javascript and jquery



    To enable or disable buttons using javascript and jQuery based on whether the input field is filled or empty.

    Introduction to disabling/enabling buttons

    Often while filling out web forms have you noticed how the submit button just won't work unless we have filled all the required fields? This is done by controlling the state of the button (enabled/disabled) based on whether the input field is filled or empty. The same principle applies to checkboxes and radio buttons.

     Logic behind toggling between disabled and enabled states of buttons

    Set button to disabled state in the beginning If the input value of the required field is empty, let the button remain disabled. (Disabled state = TRUE) If the input value of the required field is not empty, change the state of the button to enabled. (Or set disabled state = FALSE)

    Code Implementation for changing the state of the button

     1. Using Javascript

    A) HTML

    Add the following HTML Code to your editor //defining button and input field <input type="text" placeholder="fill me"> <button>Click Me</button>

    Code Explanation

    Using the above code we have defined two HTML elements namely an input text field and a button.

    B) Javascript Code

    //Program to disable or enable a button using javascript <script > let input = document.querySelector(".input"); let button = document.querySelector(".button"); button.disabled = true; //setting button state to disabled input.addEventListener("change", stateHandle); function stateHandle() { if (document.querySelector(".input").value === "") { button.disabled = true; //button remains disabled } else { button.disabled = false; //button is enabled } } </script>

    Code Explanation

    1. Now, using javascript we store a reference to each element, namely input, and button. 2. By default a button's state is enabled in HTML so by setting disabled = true, we have disabled the button for the user. 3. Then we add an event handler (addEventListener) to the input field with the event property change which monitors the interaction with elements. 4. Here we use the change property to monitor when the user types text inside the input field and run a function accordingly. 5. The function we run here is called the stateHandle() that gets activated every time there is a change in the status of the input field. 6. The function compares the value of the input field (the text field) with an empty string. 7. If the user has not typed anything, then the text field will be equal ( === ) to the empty string and the button will remain disabled (disabled = true). 8. If the user inputs text in the input field, then the button will get enabled (disabled = false).

     2. Using jQuery to enable/disable a button

    <html> <head> <title>jQuery - Enable or Disable Button</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> </head> <body> Name: <input type="text" /> <input type="submit" disabled="disabled" /> </body> <script> $(document).ready(function() { $('#tbName').on('input change', function() { if($(this).val() != '') { $('#submit').prop('disabled', false); } else { $('#submit').prop('disabled', true); } }); }); </script> </html> 1. For the jQuery method too, we start by creating an HTML button and text field (submit and tbName respectively) and setting the button to disabled state initially. 2. Here the ready() function is used to make the function available once the document has been loaded. 3. The .on() method in jquery attaches the event handler to the input field (tbName). 4. The change event will check for changes in the input field and run the function accordingly. 5. Just like in javascript, if the text field is empty the button remains disabled, else it gets enabled. 6. Here the .prop() method is used to change the state of the button.

    Visualization

    You can play around with the above code using this editor and see which part of the code does what. You can also try out different CSS options for the button etc.

    Toggle (Hide/Show) an Element

    <div id="myDIV">my DIV element</div> function toggleElement() { var myDIV = document.getElementById("myDIV"); if (myDIV.style.display === "none") { myDIV.style.display = "block"; } else { myDIV.style.display = "none"; } } function showElement() { var myDIV = document.getElementById("myDIV"); myDIV.style.display = "block"; } function hideElement() { var myDIV = document.getElementById("myDIV"); myDIV.style.display = "none"; }

    to locate string pattern in array of strings

    // Sample array of strings stringArr = [ "Hello, this is a sample string.", "Another h2 string here.", "Yet another string to search.", "<h2> string to search." ]; // Function to locate the substring function findSubstring(arr, substring) { indexarr = [] for (i = 0; i < arr.length; i++) { index = arr[i].indexOf(substring); if (index !== -1) { indexarr.push(i) } } return indexarr; } // Substring to search for targetpattern = "h2"; // Find the array of strings result = findSubstring(stringArr, targetpattern);

    to locate string pattern in object of strings

    obj = { str1: "Hello, this is a sample string.", str2: "Another example string here.", str3: "Yet another string to search." }; // Function to locate the substring index in the object of strings function findSubstring(obj, substring) { indexarr = [] for (key in obj) { if (obj.hasOwnProperty(key)) { index = obj[key].indexOf(substring); if (index !== -1) { indexarr.push(i) } } } return indexarr; } // Substring to search for targetpattern = "example"; // Find the index of the substring in the object of strings result = findSubstring(obj, targetpattern);

    batches Executing Promises



    When working with asynchronous operations in JavaScript, such as API calls, there are times when you need to limit the number of concurrent operations to prevent overloading your system or third-party services. A common scenario is executing a large number of promises in manageable batches. We’ll explore how to achieve this by writing a simple yet effective `throttleAsync` function. The Problem: Managing Concurrent Asynchronous Operations Imagine you have an array of tasks where each task is an asynchronous operation, such as making API calls. Executing all these operations simultaneously could overwhelm the system or lead to rate limiting. Instead, it’s often better to throttle these operations — processing them in smaller batches. The Solution: throttleAsync Let’s break down the code step-by-step. // Array of promises generated by the task function const callAPIs = [task(100), task(200), task(300), task(400), task(500), task(600)]; Here, we have an array of tasks. Each task simulates an asynchronous operation that resolves after a specified amount of time. // Function that returns a promise that resolves after a set time async function task(time) { return new Promise((resolve, reject) => { setTimeout( () => { resolve(`Resolved promise in time: ${time}`); }, time); }); } The `task` function returns a promise that resolves after a given number of milliseconds. This simulates a delay, similar to what you might encounter in real-world API calls. Now, let’s look at the core of this post: the `throttleAsync` function. // Function to execute promises in batches async function throttleAsync(promises, batchSize) { let result = []; for (let i = 0; i < promises.length; i += batchSize) { const batch = promises.slice(i, i + batchSize); // Execute the current batch and wait for all of them to complete let batchResult = await Promise.all(batch.map(p => p)); result.push(...batchResult); } return result; } How `throttleAsync` Works 1. Batching Promises: — The function accepts an array of promises (`callAPIs`) and a `batchSize`, indicating how many promises should be processed concurrently. — It slices the array into smaller batches of the specified size. 2. Executing Batches: — Inside the loop, each batch is processed by `Promise.all()`, which waits for all promises in the current batch to resolve. — The results of each batch are collected and stored in the `result` array. 3. Returning the Results: — After all batches have been processed, the accumulated results are returned. Using `throttleAsync` Finally, let’s see how to use the `throttleAsync` function: // Calling the function with the API promises array and batch size of 2 throttleAsync(callAPIs, 2).then((resolve) => { console.log(resolve); }).catch((error) => { console.log(error); }); In this example, we call `throttleAsync` with the `callAPIs` array and a batch size of `2`. This means the promises will be executed in pairs, ensuring that no more than two are processed simultaneously. Once all batches are processed, the results are logged to the console. Why Use `throttleAsync`? - Resource Management: Limits the number of concurrent operations, which is crucial when dealing with APIs that have rate limits or when system resources are constrained. - Better Performance: By controlling the flow of operations, you can achieve better performance, especially in environments where concurrency might otherwise lead to issues like rate limiting or memory exhaustion. Conclusion The `throttleAsync` function is a powerful yet straightforward tool for managing the execution of multiple asynchronous operations in JavaScript. By processing promises in batches, you can control the flow of operations, preventing overloads and ensuring smoother performance. Whether you’re dealing with API calls, file processing, or any other asynchronous tasks, this pattern is versatile and easy to implement.

    Wrap all the nodes within the div

    org_html = $("#slidesContainer").innerHTML; new_html = "<div id='slidesInner'>" + org_html + "</div>"; $("#slidesContainer").innerHTML = new_html;

    Storing and retrieving objects in localStorage



    LocalStorage and sessionStorage allow developers to store data persistently and temporarily. The localStorage object can be accessed shown below: localStorage.setItem("myDataKey", "My data"); localStorage.getItem("myDataKey"); // "My data" localStorage.removeItem("myDataKey"); The data stored in the localStorage object from a domain can only be accessed or modified by pages of the same origin, which — in this case — stands for protocol, domain, and port collectively. The localStorage object stores the data with no expiration date. The data will not be deleted even when the user leaves the page or closes the browser window; it will be available for future sessions.

    Using sessionStorage vs. localStorage

    SessionStorage, is nearly identical to localStorage but differs in two ways: it temporarily stores data for the specified (or current) tab and does so for only a limited period. The sessionStorage object stays active as long as the corresponding tab is open and persists data through page reloads and restorations. When a webpage is loaded into a browser tab, sessionStorage, if used, creates a new page session and assigns it to that tab. That page session is only valid for that particular origin accessed in that specific tab. Note: Data stored in each kind of Web Storage is distinct for each protocol of a given page. This means that data stored on a site accessed via HTTP is stored on a different sessionStorage object than data stored on the same site accessed via HTTPS. Using Chrome DevTools, you can view the data in both localStorage and sessionStorage objects and observe the distinctions. Here’s a screenshot depicting locating both objects in the Application tab of DevTools: Note: When the last private tab is closed, data stored in the localStorage object of a site opened in a private tab or incognito mode is cleared, which makes sense because it’s a private browsing session.

    Web Storage vs. HTTP cookies

    HTTP cookies are a conventional mechanism for storing small bits of data exchanged between the client and the server during each HTTP request. Once connected to a client, the server generates certain bits of information, saves them in a cookie file, and sends them to the client’s browser. This information is labeled with a unique ID for each user and their computer, which helps the server identify the user whenever a connection is established. However, they can be a privacy nightmare.

    How to store a JavaScript object in localStorage

    setItem(): Adds data to a Web Storage object using its two arguments, a key, and a value: localStorage.setItem("key", "value") getItem(): Returns the value of the key name that’s passed to it: localStorage.getItem("key") removeItem(): Removes a key that’s passed to it with its corresponding value: localStorage.removeItem("key") clear(): Clears all the key-value pairs in the associated storage and should be used with caution: localStorage.clear() key(): Returns the key at the specified index in the storage: localStorage.key(0) length: Returns the total number of key-value pairs stored in the associated storage: localStorage.length

     JavaScript object serialization

    Storing JavaScript object data in Web Storage is a bit tricky, as it allows you to store only string values. If we try to store a JavaScript object without first converting it to a string, we will get an [object Object] response, as shown in the image below: [object Object] is a string representation of an object instance whose value was never read at the time of storing the data, which will result in data loss. The correct way to store object data to localStorage is to first convert it to a string. This object-to-string conversion of object data is known as serialization, and turning this converted string back to object data is called deserialization. Let’s briefly discuss two important JSON methods that are responsible for object data serialization and deserialization: JSON.stringify : Converts any object value into a string JSON (serialization) JSON.parse : Turns a JSON string into its corresponding object or value (deserialization) Now, utilizing the setItem method with JSON stringify, we can easily convert a JavaScript object to a JSON string and push it to the localStorage object. Here’s a quick example to demonstrate this: const userObj = { name: "John Doe", age: 32, gender: "Male", profession: "Optician" }; localStorage.setItem("userObj", JSON.stringify(myObject)); Now, if we try to retrieve the object data without deserializing it, we will receive a JSON string instead of an object, which makes sense, as it is what we stored to localStorage. We need to deserialize this JSON string data using the JSON parse method to turn it back into a JavaScript object: let newObject = localStorage.getItem("myObject"); console.log(JSON.parse(newObject)); Here, we retrieved our previously set JavaScript object using the getItem method on the localStorage object and saved it into a variable.

     More examples of storing objects in localStorage

    Storing Date objects : Constructing an object using the current timestamp using the Date object and a random value, and saving it to or clearing it from the localStorage using button inputs Persisting remote data : Fetching remote data from a dummy API and storing it in localStorage; the network fetch in this example is only triggered when no associated data in localStorage is found

     Storing multiple objects in localStorage

    Let’s say we have a bunch of similar objects, and we want to group all of them and store them as one JSON string in the localStorage. We can turn them into an object array and then serialize them as shown below: const todos = [todo1, todo2, todo3]; localStorage.setItem("todos", JSON.stringify(todos)); If you have bigger chunks of data to work with, you might want to store each of them with separate keys, but accessing all of them quickly can be done using this namespace approach: // Storing localStorage.setItem('todos:1', JSON.stringify(todo1)); localStorage.setItem('todos:2', JSON.stringify(todo2)); // Retrieving const keys = Object.keys(localStorage).filter(key => key.startsWith('todos:')); const todos = keys.map(key => JSON.parse(localStorage.getItem(key)));

    Limitations of storing objects to localStorage

    The API provides 5-10MB of storage per origin, and the exact storage may vary depending on the browser. Keep in mind that Web Storage API operations are synchronous and block the main thread, therefore performing heavy operations using it may block other resources from loading in the browser.

    Types of data that can be stored as a JSON string

    Primitive data types like numbers, Booleans, and strings are JSON-safe, while values like functions, undefined, symbols, and Date objects are not JSON-safe. If no JSON-safe values are found during conversion, they are either excluded from an object or changed to null in an array. Note: Some of these such values can be made JSON-safe, for example, we used the toISOstring method with the Date object in this example to make it JSON-safe before pushing it to Web Storage.

    shuffle(array)

    function shuffle(array) { currentIndex = array.length; while (currentIndex != 0) { randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]]; } }

    Remove Element from an Array



    There is not a simple Array.remove method. The Array filter method remove unwanted elements by creating a new array with desired items.

    Using Splice

    The first argument specifies the begin location. The second argument specifies the number of elements to remove. The third and subsequent arguments are optional; they specify elements to be added to the array. Here we use the splice method to remove two elements starting from position three (zero based index): var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; var removed = arr.splice(2,2); An array containing the removed elements is returned by the splice method. You can see the removed array contains [3, 4] and the original array contains the remaining values. The splice method can also be used to remove a range of elements from an array. var list = ["bar", "baz", "foo", "qux"]; list.splice(0, 2); // Starting at index position 0, remove two elements ["bar", "baz"] and retains ["foo", "qux"].

    Remove Array Items By Value Using Splice

    If you know the value you want to remove from an array you can use the splice method. First you must identify the index of the target item. You then use the index as the start element and remove just one element. var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; for( var i = 0; i < arr.length; i++){ if ( arr[i] === 5) { arr.splice(i, 1); } } //=> [1, 2, 3, 4, 6, 7, 8, 9, 0] This is a simple example where the elements are integers. If you have an array of objects you would need a more sophisticated routine. This works if you only want to remove a single item. If you want to remove multiple items that match your criteria there is a glitch. As the items are removed from the array the index still increments and the next item after your matched value is skipped. The simple solution is to modify the above example to decrement the index variable so it does not skip the next item in the array. var arr = [1, 2, 3, 4, 5, 5, 6, 7, 8, 5, 9, 0]; for( var i = 0; i < arr.length; i++){ if ( arr[i] === 5) { arr.splice(i, 1); i--; } } //=> [1, 2, 3, 4, 6, 7, 8, 9, 0] In the modified example I added 2 additional 5 values to the array. I also added 'i--;' after the splice call. Now when you execute the loop it will remove every matching item. Thanks to Kristian Sletten for pointing out the issue with the loop skipping the following item.

    Removing One Element Using splice()

    The splice() method is a versatile way of removing, replacing, and/or adding elements in an array. It works similarly to splice() functions in other languages. Basically, you take an array and selectively remove portions of it (aka “splice”). The inputs to the splice() function are the index point to start at and the number of elements to remove. Also, remember that arrays are zero-indexed in JavaScript. To remove one element from a specific index in an array: ["bar", "baz", "foo", "qux"] list.splice(2, 1) // Starting at index position 2, remove one element ["bar", "baz", "qux"] list.splice(2,2) // Starting at index position 2, remove two elements ["bar", "baz"] The splice() call will return any removed elements, so you know what was actually removed.

    Removing a Range of Elements Using splice()

    Just to make sure you didn’t miss it in the previous example, it is worth calling out specifically that you can remove several consecutive elements with splice(). To remove several consecutive elements from an array: ["bar", "baz", "foo", "qux"] list.splice(0, 2) // Starting at index position 0, remove two elements ["foo", "qux"]

    Removing One Element Using pop()

    The array methods push() and pop() work on the the end of an array. The terms push() and pop() come from the idea of a stack in memory from the early days of microprocessors. This implements the idea of a Last-In-First-Out data structure (LIFO). The push() method will ADD an element to the array and the pop() method will remove one. To remove the last element of an array: ["bar", "baz", "foo", "qux"] list.pop() ["bar", "baz", "foo"]

    Removing One Element Using shift()

    The array methods shift() and unshift() work on the beginning of an array instead of the end of an array, as is the case with push() and pop(). The shift() command will remove the first element of the array and the unshift() command will add an element to the beginning of the array. To remove the first element of an array: ["bar", "baz", "foo", "qux"] list.shift() ["baz", "foo", "qux"]

    Searching and Removing a Specific Element by Value

    The indexOf() command returns the first index at which a given element can be found in the array, or -1 if it is not present. This can be used along with splice() to search for an element and then remove it, even if you don’t know where it is in the array. Let’s remove the “foo” element: ["bar", "baz", "foo", "qux"] list.splice( list.indexOf('foo'), 1 ); // Find the index position of "foo," then remove one element from that position

    Removing Multiple Specific Elements

    If to remove multiple repeating items that match the criteria. Here two 5s in array: var arr = [1, 2, 3, 4, 5, 5, 6, 7, 8, 5, 9, 0]; for( var i = 0; i < arr.length; i++){ if ( arr[i] === 5) { arr.splice(i, 1); i--; } } //=> [1, 2, 3, 4, 6, 7, 8, 9, 0] added 'i--;' after the splice call. OR: Let’s add an extra “foo” element to our array, and then remove all occurrences of “foo”: ["bar", "baz", "foo", "foo", "qux"] for( var i = list.length-1; i--;){ if ( list[i] === 'foo') list.splice(i, 1); } ["bar", "baz", "qux"]

    Remove Elements from End of Array

    Setting the length property to a value less than the current value remove from the end of an array. var ar = [1, 2, 3, 4, 5, 6]; ar.length = 4; // set length to remove elements The pop method removes the last element. var ar = [1, 2, 3, 4, 5, 6]; ar.pop(); // returns 6 console.log( ar ); // [1, 2, 3, 4, 5]

    Remove Elements from Beginning of Array

    The shift method removes the first element of array. var ar = ['zero', 'one', 'two', 'three']; ar.shift(); // returns "zero" console.log( ar ); // ["one", "two", "three"]

    Using the Array filter Method to Remove Items By Value

    Unlike the splice method, filter creates a new array. filter() does not mutate the array on which it is called, but returns a new array. filter() has a single parameter, a callback method. The callback is triggered as the filter method iterates through the array elements. It will pass three values to the callback: the current value or element, the current array index and the full array. The callback method should return either true or false. It is your responsibility to test the value (element) to see if it meets your criteria. If it does you can return true. Elements that return true are added to the new, filtered array. var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; var filtered = array.filter( function(value, index, arr){ return value > 5;} ); //filtered => [6, 7, 8, 9] //array => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] You should note a new array containing matching values is returned. The original array is left untouched. I find this useful because I often want to retain an original data source, but retrieve subsets based on different logic sets.

    to remove elements contained in another array

    myArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; toRemove = ['b', 'c', 'g']; filteredArray = myArray.filter( function(x) { return toRemove.indexOf(x) < 0;} );

    The Lodash Array Remove Method

    Sometimes utility libraries are the best way to solve more complex problems. Lodash provides a rich set of array manipulation methods, one being remove. The Lodash remove method works much like the array filter method, but sort of in reverse. It does not save the original array values, but removes matching elements. It returns the matching elements as a new array. var array = [1, 2, 3, 4];var evens = _.remove(array, function(n) { return n % 2 === 0;});console.log(array);// => [1, 3]console.log(evens);// => [2, 4]

    Making a Remove Method

    function arrayRemove(arr, value) { return arr.filter(function(ele){ return ele != value; }); } var result = arrayRemove(array, 6); // result = [1, 2, 3, 4, 5, 7, 8, 9, 0] This method is simple, it assumes simple values like numbers or strings. You could modify this method to use a customcomparison method, but I think it would be easier to just use the filter method directly.

    Explicitly Remove Array Elements Using the Delete Operator

    You can remove specific array elements using the delete operator: var ar = [1, 2, 3, 4, 5, 6]; delete ar[4]; // delete element with index 4 console.log( ar ); // [1, 2, 3, 4, undefined, 6] alert( ar ); // 1,2,3,4,,6 Using the delete operator does not affect the length property. Nor does it affect the indexes of subsequent elements. The array becomes sparse, which is a fancy way of saying the deleted item is not removed but becomes undefined. Compare using delete with the splice method described below. The delete operator is designed to remove properties from JavaScript objects, which arrays are objects. The reason the element is not actually removed from the array is the delete operator is more about freeing memory than deleting an element. The memory is freed when there are no more references to the value.

    Clear or Reset a JavaScript Array

    What if you want to empty an entire array and just dump all of it's elements? There are a couple of techniques you can use to create an empty or new array. The simplest and fastest technique is to set an array variable to an empty array: var ar = [1, 2, 3, 4, 5, 6]; //do stuffar = []; //a new, empty array! The problem this can create is when you have references to the variable. The references to this variable will not change, they will still hold the original array's values. This of course can create a bug🐛. This is an over simplified example of this scenario: var arr1 = [1, 2, 3, 4, 5, 6]; var arr2 = arr1; // Reference arr1 by another variable arr1 = []; console.log(arr2); // Output [1, 2, 3, 4, 5, 6] A simple trick to clear an array is to set its length property to 0. var ar = [1, 2, 3, 4, 5, 6]; console.log(ar); // Output [1, 2, 3, 4, 5, 6] ar.length = 0; console.log(ar); // Output [] Another, sort of unnatural technique, is to use the splice method, passing the array length as the 2nd parameter. This will return a copy of the original elements, which may be handy for your scenario. var ar = [1, 2, 3, 4, 5, 6]; console.log(ar); // Output [1, 2, 3, 4, 5, 6] ar.splice(0, ar.length); console.log(ar); // Output [] The last two techniques don't create a new array, but change the array's elements. This means references should also update. There is another way, using a while loop. It feels a little odd to me, but at the same time looks fancy, so it may impress some friends! var ar = [1, 2, 3, 4, 5, 6]; console.log(ar); // Output [1, 2, 3, 4, 5, 6] while (ar.length) { ar.pop(); } console.log(ar); // Output [] Not a way I would go about clearing a JavaScript array, but it works and it is readable. Some performance test have also shown this to be the fastest technique, so maybe it is better than I originally thought!

    Summary

    Removing JavaScript Array items is important to managing your data. There is not a single 'remove' method available, but there are different methods and techniques you can use to purge unwanted array items.

    Load scripts

    jsURL = "abc" // js name loadScript(jsURL) function loadScript(jsURL) { var script = document.createElement('script'); script.src = "./aPath/scripts/" + jsURL + ".js"; script.onload = function() { // this is callback function linksArray = eval(jsURL) itemLength = linksArray.length alert(jsURL + " put into linksArray, usr r to randomOpen") } document.getElementsByTagName('head')[0].appendChild(script); } // Get the first script element on the page var ref = w.document.getElementsByTagName( 'script' )[ 0 ]; // Create a new script element var script = w.document.createElement( 'script' ); // Set the script element `src` script.src = 'path-to-your-javascript-file.js'; // Inject the script into the DOM ref.parentNode.insertBefore( script, ref ); This simply append to head var script = document.createElement('script'); script.src = urladdr; script.onload = function() { ....// remember to put all awaiting jobs inside here, otherwise awaiting jobs will be omited } document.getElementsByTagName('head')[0].appendChild(script);

    document on ready load script

    $(document).ready(function(){ $('<script/>',{type:'text/javascript', src:'http://williamkpchan.github.io/LibDocs/readbook.js'}).appendTo('head'); });

    Load JavaScript on demand

    function loadJs(url) { var script = document.createElement('script'); script.setAttribute('src', url); script.setAttribute('type', 'text/javascript'); document.getElementsByTagName("head")[0].appendChild(script); };

    load Script by Promise

    function loadScript(url) { return new Promise((resolve, reject) => { // 創建一個新的 script 元素 const script = document.createElement('script'); script.url = url; script.type = 'text/javascript'; // 定義 onload 事件處理程序 script.onload = () => { resolve(script); // 腳本加載成功,調用 resolve }; // 將 script 元素添加到文檔中 document.head.appendChild(script); }); } // 加載腳本 const script = await loadScript('https://example.com/your-script.js'); // 替換為你的腳本 URL

    list all array names in web page

    // define sample arraya users = []; products = []; orders = []; settings = []; listItem = "Array names: " // list all window objects for (variableName in window) { if (window[variableName] instanceof Array) { // 檢查是否為數組 listItem = listItem + ", " + variableName; // 顯示數組名稱 console.log("listItem ",listItem) } } console.log(listItem)